ctdb-2.5.1.dfsg/0000755000175000017500000000000012254276664013245 5ustar mathieumathieuctdb-2.5.1.dfsg/README0000644000175000017500000000056412245023514014112 0ustar mathieumathieuThis is the release version of CTDB, a clustered implementation of TDB database used by Samba and other projects to store temporary data. This software is freely distributable under the GNU public license, a copy of which you should have received with this software (in a file called COPYING). For documentation on CTDB, please visit CTDB website http://ctdb.samba.org. ctdb-2.5.1.dfsg/README.Coding0000644000175000017500000001446012245023514015314 0ustar mathieumathieu## ## Coding conventions in the Samba 3.0 tree ## =========== Quick Start =========== Coding style guidelines are about reducing the number of unnecessary reformatting patches and making things easier developers to work together. You don't have to like them or even agree with them, but once put in place we all have to abide by them (or vote to change them). However, coding style should never outweigh coding itself and so the the guidelines described here are hopefully easier enough to follow as they are very common and supported by tools and editors. The basic style, also mentioned in the SAMBA_4_0/prog_guide.txt is the Linux kernel coding style (See Documentation/CodingStyle in the kernel source tree). The closely matches what most Samba developers use already anyways. But to save you the trouble of reading the Linux kernel style guide, here are the highlights. * Maximum Line Width is 80 Characters The reason is not for people with low-res screens but rather sticking to 80 columns prevents you from easily nesting more than one level of if statements or other code blocks. Use source/script/count_80_col.pl to check your changes. * Use 8 Space Tabs to Indent No whitespace filler. * No Trailing Whitespace Use source/script/strip_trail_ws.pl to clean you files before committing. * Follow the K&R guidelines. We won't go throw them all here. You have a copy of "The C Programming Language" anyways right? You can also use the format_indent.sh script found in source/script/ if all else fails. ============ Editor Hints ============ Emacs ----- Add the follow to your $HOME/.emacs file: (add-hook 'c-mode-hook (lambda () (c-set-style "linux") (c-toggle-auto-state))) Vi -- (Thanks to SATOH Fumiyasu for these hints): For the basic vi editor including with all variants of *nix, add the following to $HOME/.exrc: set tabstop=8 set shiftwidth=8 For Vim, the following settings in $HOME/.vimrc will also deal with displaying trailing whitespace: if has("syntax") && (&t_Co > 2 || has("gui_running")) syntax on function! ActivateInvisibleCharIndicator() syntax match TrailingSpace "[ \t]\+$" display containedin=ALL highlight TrailingSpace ctermbg=Red endf autocmd BufNewFile,BufRead * call ActivateInvisibleCharIndicator() endif " Show tabs, trailing whitespace, and continued lines visually set list listchars=tab:»·,trail:·,extends:… " highlight overly long lines same as TODOs. set textwidth=80 autocmd BufNewFile,BufRead *.c,*.h exec 'match Todo /\%>' . &textwidth . 'v.\+/' ========================= FAQ & Statement Reference ========================= Comments -------- Comments should always use the standard C syntax. I.e. /* ... */. C++ style comments are not currently allowed. Indention & Whitespace & 80 columns ----------------------------------- To avoid confusion, indentations are to be 8 character with tab (not 8 ' ' characters. When wrapping parameters for function calls, alignment parameter list with the first parameter on the previous line. Use tabs to get as close as possible and then fill in the final 7 characters or less with whitespace. For example, var1 = foo(arg1, arg2, arg3); The previous example is intended to illustrate alignment of function parameters across lines and not as encourage for gratuitous line splitting. Never split a line before columns 70 - 79 unless you have a really good reason. Be smart about formatting. If, switch, & Code blocks ------------------------- Always follow an 'if' keyword with a space but don't include additional spaces following or preceding the parentheses in the conditional. This is good: if (x == 1) This is bad: if ( x == 1 ) Yes we have a lot of code that uses the second form and we are trying to clean it up without being overly intrusive. Note that this is a rule about parentheses following keywords and not functions. Don't insert a space between the name and left parentheses when invoking functions. Braces for code blocks used by for, if, switch, while, do..while, etc... should begin on the same line as the statement keyword and end on a line of their own. NOTE: Functions are different and the beginning left brace should begin on a line of its own. If the beginning statement has to be broken across lines due to length, the beginning brace should be on a line of its own. The exception to the ending rule is when the closing brace is followed by another language keyword such as else or the closing while in a do..while loop. Good examples: if (x == 1) { printf("good\n"); } for (x=1; x<10; x++) { print("%d\n", x); } do { printf("also good\n"); } while (1); Bad examples: while (1) { print("I'm in a loop!\n"); } Goto ---- While many people have been academically taught that goto's are fundamentally evil, then can greatly enhance readability and reduce memory leaks when used as the single exit point from a function. But in no Samba world what so ever is a goto outside of a function or block of code a good idea. Good Examples: int function foo(int y) { int *z = NULL; int ret = 0; if ( y < 10 ) { z = malloc(sizeof(int)*y); if (!z) { ret = 1; goto done; } } print("Allocated %d elements.\n", y); done: if (z) free(z); return ret; } Checking Pointer Values ----------------------- When invoking functions that return pointer values, either of the following are acceptable. Use you best judgement and choose the more readable option. Remember that many other people will review it. if ((x = malloc(sizeof(short)*10)) == NULL ) { fprintf(stderr, "Unable to alloc memory!\n"); } or x = malloc(sizeof(short)*10); if (!x) { fprintf(stderr, "Unable to alloc memory!\n"); } Primitive Data Types -------------------- Samba has large amounts of historical code which makes use of data types commonly supported by the C99 standard. However, at the time such types as boolean and exact width integers did not exist and Samba developers were forced to provide their own. Now that these types are guaranteed to be available either as part of the compiler C99 support or from lib/replace/, new code should adhere to the following conventions: * Booleans are of type "bool" (not BOOL) * Boolean values are "true" and "false" (not True or False) * Exact width integers are of type [u]int[8|16|32|64]_t ctdb-2.5.1.dfsg/.bzrignore0000644000175000017500000000032512245023514015227 0ustar mathieumathieuconfig.status Makefile bin config.log push.sh ctdb_test config.cache configure config.h config.h.in nodes-ssh.txt TAGS ctdb-0 ctdb-1 ctdb-2 ctdb-3 nodes.txt TAGS web/packages rec.lock test.db sock.1 sock.3 sock.4 ctdb-2.5.1.dfsg/aclocal.m40000644000175000017500000000003212245023514015060 0ustar mathieumathieum4_include(libreplace.m4) ctdb-2.5.1.dfsg/doc/0000755000175000017500000000000012245332464014001 5ustar mathieumathieuctdb-2.5.1.dfsg/doc/ping_pong.1.html0000644000175000017500000000464112245332462017011 0ustar mathieumathieuping_pong

Name

ping_pong — measures the ping-pong byte range lock latency

Synopsis

ping_pong { -r | -w | -rw } [-m] [-c] {FILENAME} {NUM-LOCKS}

DESCRIPTION

ping_pong measures the byte range lock latency. It is especially useful on a cluster of nodes sharing a common lock manager as it will give some indication of the lock manager's performance under stress.

FILENAME is a file on shared storage to use for byte range locking tests.

NUM-LOCKS is the number of byte range locks, so needs to be (strictly) greater than the number of nodes in the cluster.

OPTIONS

-r

test read performance

-w

test write performance

-m

use mmap

-c

validate the locks

EXAMPLES

Testing lock coherence

      ping_pong test.dat N
    

Testing lock coherence with lock validation

      ping_pong -c test.dat N
    

Testing IO coherence

      ping_pong -rw test.dat N
    
ctdb-2.5.1.dfsg/doc/ltdbtool.10000644000175000017500000001231412245332461015704 0ustar mathieumathieu'\" t .\" Title: ltdbtool .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "LTDBTOOL" "1" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ltdbtool \- manipulate CTDB\*(Aqs local TDB files .SH "SYNOPSIS" .HP \w'\fBltdbtool\fR\ 'u \fBltdbtool\fR [\fIOPTION\fR...] {\fICOMMAND\fR} [\fICOMMAND\-ARGS\fR] .SH "DESCRIPTION" .PP ltdbtool is a utility to manipulate CTDB\*(Aqs local TDB databases (LTDBs) without connecting to a CTDB daemon\&. .PP It can be used to: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} dump the contents of a LTDB, optionally printing the CTDB record header information, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} convert between an LTDB and a non\-clustered tdb by adding or removing CTDB headers and .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} convert between 64 and 32 bit LTDBs where the CTDB record headers differ by 4 bytes of padding\&. .RE .SH "OPTIONS" .PP \-e .RS 4 Dump empty records\&. These are normally excluded\&. .RE .PP \-p .RS 4 Dump with header information, similar to "ctdb catdb"\&. .RE .PP \-s {0 | 32 | 64} .RS 4 Specify how to determine the CTDB record header size for the input database: .PP 0 .RS 4 no CTDB header .RE .PP 32 .RS 4 CTDB header size of a 32 bit system (20 bytes) .RE .PP 64 .RS 4 CTDB header size of a 64 bit system (24 bytes) .RE .sp The default is 32 or 64 depending on the system architecture\&. .RE .PP \-o {0 | 32 | 64} .RS 4 Specify how to determine the CTDB record header size for the output database, see \-s\&. .RE .PP \-S \fISIZE\fR .RS 4 Explicitly specify the CTDB record header SIZE of the input database in bytes\&. .RE .PP \-O \fISIZE\fR .RS 4 Explicitly specify the CTDB record header SIZE for the output database in bytes\&. .RE .PP \-h .RS 4 Print help text\&. .RE .SH "COMMANDS" .PP help .RS 4 Print help text\&. .RE .PP dump \fIIDB\fR .RS 4 Dump the contents of an LTDB input file IDB to standard output in a human\-readable format\&. .RE .PP convert \fIIDB\fR \fIODB\fR .RS 4 Copy an LTDB input file IDB to output file ODB, optionally adding or removing CTDB headers\&. .RE .SH "EXAMPLES" .PP Print a local tdb in "tdbdump" style: .sp .if n \{\ .RS 4 .\} .nf ltdbtool dump idmap2\&.tdb\&.0 .fi .if n \{\ .RE .\} .PP Print a local tdb with header information similar to "ctdb catdb": .sp .if n \{\ .RS 4 .\} .nf ltdbtool dump \-p idmap2\&.tdb\&.0 .fi .if n \{\ .RE .\} .PP Strip the CTDB headers from records: .sp .if n \{\ .RS 4 .\} .nf ltdbtool convert \-o0 idmap2\&.tdb\&.0 idmap\&.tdb .fi .if n \{\ .RE .\} .PP Strip 64 bit CTDB headers from records, running on i386: .sp .if n \{\ .RS 4 .\} .nf ltdbtool convert \-s64 \-o0 idmap2\&.tdb\&.0 idmap\&.tdb .fi .if n \{\ .RE .\} .PP Strip the CTDB headers from records by piping through tdbrestore: .sp .if n \{\ .RS 4 .\} .nf ltdbtool dump idmap2\&.tdb\&.0 | tdbrestore idmap\&.tdb .fi .if n \{\ .RE .\} .PP Convert a local tdb from a 64 bit system for usage on a 32 bit system: .sp .if n \{\ .RS 4 .\} .nf ltdbtool convert \-s64 \-o32 idmap2\&.tdb\&.0 idmap2\&.tdb\&.1 .fi .if n \{\ .RE .\} .PP Add a default header: .sp .if n \{\ .RS 4 .\} .nf ltdbtool convert \-s0 idmap\&.tdb idmap2\&.tdb\&.0 .fi .if n \{\ .RE .\} .SH "SEE ALSO" .PP \fBctdb\fR(1), \fBtdbdump\fR(1), \fBtdbrestore\fR(1), \fBctdb\fR(7), \m[blue]\fB\%http://ctdb.samba.org/\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Gregor Beck .SH "COPYRIGHT" .br Copyright \(co 2011 Gregor Beck, Michael Adam .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp ctdb-2.5.1.dfsg/doc/ctdb.7.xml0000644000175000017500000007302412245023514015603 0ustar mathieumathieu ctdb 7 ctdb CTDB - clustered TDB database ctdb Clustered TDB DESCRIPTION CTDB is a clustered database component in clustered Samba that provides a high-availability load-sharing CIFS server cluster. The main functions of CTDB are: Provide a clustered version of the TDB database with automatic rebuild/recovery of the databases upon node failures. Monitor nodes in the cluster and services running on each node. Manage a pool of public IP addresses that are used to provide services to clients. Alternatively, CTDB can be used with LVS. Combined with a cluster filesystem CTDB provides a full high-availablity (HA) environment for services such as clustered Samba, NFS and other services. ANATOMY OF A CTDB CLUSTER A CTDB cluster is a collection of nodes with 2 or more network interfaces. All nodes provide network (usually file/NAS) services to clients. Data served by file services is stored on shared storage (usually a cluster filesystem) that is accessible by all nodes. CTDB provides an "all active" cluster, where services are load balanced across all nodes. Private vs Public addresses Each node in a CTDB cluster has multiple IP addresses assigned to it: A single private IP address that is used for communication between nodes. One or more public IP addresses that are used to provide NAS or other services. Private address Each node is configured with a unique, permanently assigned private address. This address is configured by the operating system. This address uniquely identifies a physical node in the cluster and is the address that CTDB daemons will use to communicate with the CTDB daemons on other nodes. Private addresses are listed in the file specified by the CTDB_NODES configuration variable (see ctdbd.conf 5, default /etc/ctdb/nodes). This file contains the list of private addresses for all nodes in the cluster, one per line. This file must be the same on all nodes in the cluster. Private addresses should not be used by clients to connect to services provided by the cluster. It is strongly recommended that the private addresses are configured on a private network that is separate from client networks. Example /etc/ctdb/nodes for a four node cluster: 192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.4 Public addresses Public addresses are used to provide services to clients. Public addresses are not configured at the operating system level and are not permanently associated with a particular node. Instead, they are managed by CTDB and are assigned to interfaces on physical nodes at runtime. The CTDB cluster will assign/reassign these public addresses across the available healthy nodes in the cluster. When one node fails, its public addresses will be taken over by one or more other nodes in the cluster. This ensures that services provided by all public addresses are always available to clients, as long as there are nodes available capable of hosting this address. The public address configuration is stored in a file on each node specified by the CTDB_PUBLIC_ADDRESSES configuration variable (see ctdbd.conf 5, recommended /etc/ctdb/public_addresses). This file contains a list of the public addresses that the node is capable of hosting, one per line. Each entry also contains the netmask and the interface to which the address should be assigned. Example /etc/ctdb/public_addresses for a node that can host 4 public addresses, on 2 different interfaces: 10.1.1.1/24 eth1 10.1.1.2/24 eth1 10.1.2.1/24 eth2 10.1.2.2/24 eth2 In many cases the public addresses file will be the same on all nodes. However, it is possible to use different public address configurations on different nodes. Example: 4 nodes partitioned into two subgroups: Node 0:/etc/ctdb/public_addresses 10.1.1.1/24 eth1 10.1.1.2/24 eth1 Node 1:/etc/ctdb/public_addresses 10.1.1.1/24 eth1 10.1.1.2/24 eth1 Node 2:/etc/ctdb/public_addresses 10.1.2.1/24 eth2 10.1.2.2/24 eth2 Node 3:/etc/ctdb/public_addresses 10.1.2.1/24 eth2 10.1.2.2/24 eth2 In this example nodes 0 and 1 host two public addresses on the 10.1.1.x network while nodes 2 and 3 host two public addresses for the 10.1.2.x network. Public address 10.1.1.1 can be hosted by either of nodes 0 or 1 and will be available to clients as long as at least one of these two nodes are available. If both nodes 0 and 1 become unavailable then public address 10.1.1.1 also becomes unavailable. 10.1.1.1 can not be failed over to nodes 2 or 3 since these nodes do not have this public address configured. The ctdb ip command can be used to view the current assignment of public addresses to physical nodes. Node status The current status of each node in the cluster can be viewed by the ctdb status command. A node can be in one of the following states: OK This node is healthy and fully functional. It hosts public addresses to provide services. DISCONNECTED This node is not reachable by other nodes via the private network. It is not currently participating in the cluster. It does not host public addresses to provide services. It might be shut down. DISABLED This node has been administratively disabled. This node is partially functional and participates in the cluster. However, it does not host public addresses to provide services. UNHEALTHY A service provided by this node has failed a health check and should be investigated. This node is partially functional and participates in the cluster. However, it does not host public addresses to provide services. Unhealthy nodes should be investigated and may require an administrative action to rectify. BANNED CTDB is not behaving as designed on this node. For example, it may have failed too many recovery attempts. Such nodes are banned from participating in the cluster for a configurable time period before they attempt to rejoin the cluster. A banned node does not host public addresses to provide services. All banned nodes should be investigated and may require an administrative action to rectify. STOPPED This node has been administratively exclude from the cluster. A stopped node does no participate in the cluster and does not host public addresses to provide services. This state can be used while performing maintenance on a node. PARTIALLYONLINE A node that is partially online participates in a cluster like a healthy (OK) node. Some interfaces to serve public addresses are down, but at least one interface is up. See also ctdb ifaces. CAPABILITIES Cluster nodes can have several different capabilities enabled. These are listed below. RECMASTER Indicates that a node can become the CTDB cluster recovery master. The current recovery master is decided via an election held by all active nodes with this capability. Default is YES. LMASTER Indicates that a node can be the location master (LMASTER) for database records. The LMASTER always knows which node has the latest copy of a record in a volatile database. Default is YES. LVS Indicates that a node is configued in Linux Virtual Server (LVS) mode. In this mode the entire CTDB cluster uses one single public address for the entire cluster instead of using multiple public addresses in failover mode. This is an alternative to using a load-balancing layer-4 switch. See the LVS section for more details. NATGW Indicates that this node is configured to become the NAT gateway master in a NAT gateway group. See the NAT GATEWAY section for more details. The RECMASTER and LMASTER capabilities can be disabled when CTDB is used to create a cluster spanning across WAN links. In this case CTDB acts as a WAN accelerator. LVS LVS is a mode where CTDB presents one single IP address for the entire cluster. This is an alternative to using public IP addresses and round-robin DNS to loadbalance clients across the cluster. This is similar to using a layer-4 loadbalancing switch but with some restrictions. In this mode the cluster selects a set of nodes in the cluster and loadbalance all client access to the LVS address across this set of nodes. This set of nodes are all LVS capable nodes that are HEALTHY, or if no HEALTHY nodes exists all LVS capable nodes regardless of health status. LVS will however never loadbalance traffic to nodes that are BANNED, STOPPED, DISABLED or DISCONNECTED. The ctdb lvs command is used to show which nodes are currently load-balanced across. One of the these nodes are elected as the LVSMASTER. This node receives all traffic from clients coming in to the LVS address and multiplexes it across the internal network to one of the nodes that LVS is using. When responding to the client, that node will send the data back directly to the client, bypassing the LVSMASTER node. The command ctdb lvsmaster will show which node is the current LVSMASTER. The path used for a client I/O is: Client sends request packet to LVSMASTER. LVSMASTER passes the request on to one node across the internal network. Selected node processes the request. Node responds back to client. This means that all incoming traffic to the cluster will pass through one physical node, which limits scalability. You can send more data to the LVS address that one physical node can multiplex. This means that you should not use LVS if your I/O pattern is write-intensive since you will be limited in the available network bandwidth that node can handle. LVS does work wery well for read-intensive workloads where only smallish READ requests are going through the LVSMASTER bottleneck and the majority of the traffic volume (the data in the read replies) goes straight from the processing node back to the clients. For read-intensive i/o patterns you can acheive very high throughput rates in this mode. Note: you can use LVS and public addresses at the same time. If you use LVS, you must have a permanent address configured for the public interface on each node. This address must be routable and the cluster nodes must be configured so that all traffic back to client hosts are routed through this interface. This is also required in order to allow samba/winbind on the node to talk to the domain controller. This LVS IP address can not be used to initiate outgoing traffic. Make sure that the domain controller and the clients are reachable from a node before you enable LVS. Also ensure that outgoing traffic to these hosts is routed out through the configured public interface. Configuration To activate LVS on a CTDB node you must specify the CTDB_PUBLIC_INTERFACE and CTDB_LVS_PUBLIC_IP configuration variables. Setting the latter variable also enables the LVS capability on the node at startup. Example: CTDB_PUBLIC_INTERFACE=eth1 CTDB_LVS_PUBLIC_IP=10.1.1.237 NAT GATEWAY NAT gateway (NATGW) is an optional feature that is used to configure fallback routing for nodes. This allows cluster nodes to connect to external services (e.g. DNS, AD, NIS and LDAP) when they do not host any public addresses (e.g. when they are unhealthy). This also applies to node startup because CTDB marks nodes as UNHEALTHY until they have passed a "monitor" event. In this context, NAT gateway helps to avoid a "chicken and egg" situation where a node needs to access an external service to become healthy. Another way of solving this type of problem is to assign an extra static IP address to a public interface on every node. This is simpler but it uses an extra IP address per node, while NAT gateway generally uses only one extra IP address. Operation One extra NATGW public address is assigned on the public network to each NATGW group. Each NATGW group is a set of nodes in the cluster that shares the same NATGW address to talk to the outside world. Normally there would only be one NATGW group spanning an entire cluster, but in situations where one CTDB cluster spans multiple physical sites it might be useful to have one NATGW group for each site. There can be multiple NATGW groups in a cluster but each node can only be member of one NATGW group. In each NATGW group, one of the nodes is selected by CTDB to be the NATGW master and the other nodes are consider to be NATGW slaves. NATGW slaves establish a fallback default route to the NATGW master via the private network. When a NATGW slave hosts no public IP addresses then it will use this route for outbound connections. The NATGW master hosts the NATGW public IP address and routes outgoing connections from slave nodes via this IP address. It also establishes a fallback default route. Configuration NATGW is usually configured similar to the following example configuration: CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24 CTDB_NATGW_PUBLIC_IP=10.0.0.227/24 CTDB_NATGW_PUBLIC_IFACE=eth0 CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1 Normally any node in a NATGW group can act as the NATGW master. Some configurations may have special nodes that lack connectivity to a public network. In such cases, CTDB_NATGW_SLAVE_ONLY can be used to limit the NATGW functionality of thos nodes. See the NAT GATEWAY section in ctdb.conf 5 for more details of NATGW configuration. Implementation details When the NATGW functionality is used, one of the nodes is selected to act as a NAT gateway for all the other nodes in the group when they need to communicate with the external services. The NATGW master is selected to be a node that is most likely to have usable networks. The NATGW master hosts the NATGW public IP address CTDB_NATGW_PUBLIC_IP on the configured public interfaces CTDB_NATGW_PUBLIC_IFACE and acts as a router, masquerading outgoing connections from slave nodes via this IP address. It also establishes a fallback default route to the configured default gateway CTDB_NATGW_DEFAULT_GATEWAY with a metric of 10. A metric 10 route is used so it can co-exist with other default routes that may be available. A NATGW slave establishes its fallback default route to the NATGW master via the private network CTDB_NATGW_PRIVATE_NETWORKwith a metric of 10. This route is used for outbound connections when no other default route is available because the node hosts no public addresses. A metric 10 routes is used so that it can co-exist with other default routes that may be available when the node is hosting public addresses. This is implemented in the 11.natgw eventscript. Please see the eventscript file for the finer details. POLICY ROUTING Policy routing is an optional CTDB feature to support complex network topologies. Public addresses may be spread across several different networks (or VLANs) and it may not be possible to route packets from these public addresses via the system's default route. Therefore, CTDB has support for policy routing via the 13.per_ip_routing eventscript. This allows routing to be specified for packets sourced from each public address. The routes are added and removed as CTDB moves public addresses between nodes. Configuration variables There are 4 configuration variables related to policy routing: CTDB_PER_IP_ROUTING_CONF, CTDB_PER_IP_ROUTING_RULE_PREF, CTDB_PER_IP_ROUTING_TABLE_ID_LOW, CTDB_PER_IP_ROUTING_TABLE_ID_HIGH. See the POLICY ROUTING section in ctdbd.conf 5 for more details. Configuration The format of each line of CTDB_PER_IP_ROUTING_CONF is: <public_address> <network> [ <gateway> ] Leading whitespace is ignored and arbitrary whitespace may be used as a separator. Lines that have a "public address" item that doesn't match an actual public address are ignored. This means that comment lines can be added using a leading character such as '#', since this will never match an IP address. A line without a gateway indicates a link local route. For example, consider the configuration line: 192.168.1.99 192.168.1.1/24 If the corresponding public_addresses line is: 192.168.1.99/24 eth2,eth3 CTDB_PER_IP_ROUTING_RULE_PREF is 100, and CTDB adds the address to eth2 then the following routing information is added: ip rule add from 192.168.1.99 pref 100 table ctdb.192.168.1.99 ip route add 192.168.1.0/24 dev eth2 table ctdb.192.168.1.99 This causes traffic from 192.168.1.1 to 192.168.1.0/24 go via eth2. The ip rule command will show (something like - depending on other public addresses and other routes on the system): 0: from all lookup local 100: from 192.168.1.99 lookup ctdb.192.168.1.99 32766: from all lookup main 32767: from all lookup default ip route show table ctdb.192.168.1.99 will show: 192.168.1.0/24 dev eth2 scope link The usual use for a line containing a gateway is to add a default route corresponding to a particular source address. Consider this line of configuration: 192.168.1.99 0.0.0.0/0 192.168.1.1 In the situation described above this will cause an extra routing command to be executed: ip route add 0.0.0.0/0 via 192.168.1.1 dev eth2 table ctdb.192.168.1.99 With both configuration lines, ip route show table ctdb.192.168.1.99 will show: 192.168.1.0/24 dev eth2 scope link default via 192.168.1.1 dev eth2 Sample configuration Here is a more complete example configuration. /etc/ctdb/public_addresses: 192.168.1.98 eth2,eth3 192.168.1.99 eth2,eth3 /etc/ctdb/policy_routing: 192.168.1.98 192.168.1.0/24 192.168.1.98 192.168.200.0/24 192.168.1.254 192.168.1.98 0.0.0.0/0 192.168.1.1 192.168.1.99 192.168.1.0/24 192.168.1.99 192.168.200.0/24 192.168.1.254 192.168.1.99 0.0.0.0/0 192.168.1.1 The routes local packets as expected, the default route is as previously discussed, but packets to 192.168.200.0/24 are routed via the alternate gateway 192.168.1.254. NOTIFICATION SCRIPT When certain state changes occur in CTDB, it can be configured to perform arbitrary actions via a notification script. For example, sending SNMP traps or emails when a node becomes unhealthy or similar. This is activated by setting the CTDB_NOTIFY_SCRIPT configuration variable. The specified script must be executable. Use of the provided /etc/ctdb/notify.sh script is recommended. It executes files in /etc/ctdb/notify.d/. CTDB currently generates notifications after CTDB changes to these states: init setup startup healthy unhealthy DEBUG LEVELS Valid values for DEBUGLEVEL are: EMERG (-3) ALERT (-2) CRIT (-1) ERR (0) WARNING (1) NOTICE (2) INFO (3) DEBUG (4) REMOTE CLUSTER NODES It is possible to have a CTDB cluster that spans across a WAN link. For example where you have a CTDB cluster in your datacentre but you also want to have one additional CTDB node located at a remote branch site. This is similar to how a WAN accelerator works but with the difference that while a WAN-accelerator often acts as a Proxy or a MitM, in the ctdb remote cluster node configuration the Samba instance at the remote site IS the genuine server, not a proxy and not a MitM, and thus provides 100% correct CIFS semantics to clients. See the cluster as one single multihomed samba server where one of the NICs (the remote node) is very far away. NOTE: This does require that the cluster filesystem you use can cope with WAN-link latencies. Not all cluster filesystems can handle WAN-link latencies! Whether this will provide very good WAN-accelerator performance or it will perform very poorly depends entirely on how optimized your cluster filesystem is in handling high latency for data and metadata operations. To activate a node as being a remote cluster node you need to set the following two parameters in /etc/sysconfig/ctdb for the remote node: CTDB_CAPABILITY_LMASTER=no CTDB_CAPABILITY_RECMASTER=no Verify with the command "ctdb getcapabilities" that that node no longer has the recmaster or the lmaster capabilities. SEE ALSO ctdb 1, ctdbd 1, ctdbd_wrapper 1, ltdbtool 1, onnode 1, ping_pong 1, ctdbd.conf 5, ctdb-tunables 7, This documentation was written by Ronnie Sahlberg, Amitay Isaacs, Martin Schwenke 2007 Andrew Tridgell Ronnie Sahlberg This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb-2.5.1.dfsg/doc/ltdbtool.1.xml0000644000175000017500000001674112245023514016507 0ustar mathieumathieu ltdbtool 1 ctdb CTDB - clustered TDB database ltdbtool manipulate CTDB's local TDB files ltdbtool OPTION COMMAND COMMAND-ARGS DESCRIPTION ltdbtool is a utility to manipulate CTDB's local TDB databases (LTDBs) without connecting to a CTDB daemon. It can be used to: dump the contents of a LTDB, optionally printing the CTDB record header information, convert between an LTDB and a non-clustered tdb by adding or removing CTDB headers and convert between 64 and 32 bit LTDBs where the CTDB record headers differ by 4 bytes of padding. OPTIONS -e Dump empty records. These are normally excluded. -p Dump with header information, similar to "ctdb catdb". -s 0 32 64 Specify how to determine the CTDB record header size for the input database: 0 no CTDB header 32 CTDB header size of a 32 bit system (20 bytes) 64 CTDB header size of a 64 bit system (24 bytes) The default is 32 or 64 depending on the system architecture. -o 0 32 64 Specify how to determine the CTDB record header size for the output database, see -s. -S SIZE Explicitly specify the CTDB record header SIZE of the input database in bytes. -O SIZE Explicitly specify the CTDB record header SIZE for the output database in bytes. -h Print help text. COMMANDS help Print help text. dump IDB Dump the contents of an LTDB input file IDB to standard output in a human-readable format. convert IDB ODB Copy an LTDB input file IDB to output file ODB, optionally adding or removing CTDB headers. EXAMPLES Print a local tdb in "tdbdump" style: ltdbtool dump idmap2.tdb.0 Print a local tdb with header information similar to "ctdb catdb": ltdbtool dump -p idmap2.tdb.0 Strip the CTDB headers from records: ltdbtool convert -o0 idmap2.tdb.0 idmap.tdb Strip 64 bit CTDB headers from records, running on i386: ltdbtool convert -s64 -o0 idmap2.tdb.0 idmap.tdb Strip the CTDB headers from records by piping through tdbrestore: ltdbtool dump idmap2.tdb.0 | tdbrestore idmap.tdb Convert a local tdb from a 64 bit system for usage on a 32 bit system: ltdbtool convert -s64 -o32 idmap2.tdb.0 idmap2.tdb.1 Add a default header: ltdbtool convert -s0 idmap.tdb idmap2.tdb.0 SEE ALSO ctdb 1, tdbdump 1, tdbrestore 1, ctdb 7, This documentation was written by Gregor Beck 2011 Gregor Beck Michael Adam This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb-2.5.1.dfsg/doc/ctdb.70000644000175000017500000006063412245332463015015 0ustar mathieumathieu'\" t .\" Title: ctdb .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "CTDB" "7" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ctdb \- Clustered TDB .SH "DESCRIPTION" .PP CTDB is a clustered database component in clustered Samba that provides a high\-availability load\-sharing CIFS server cluster\&. .PP The main functions of CTDB are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Provide a clustered version of the TDB database with automatic rebuild/recovery of the databases upon node failures\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Monitor nodes in the cluster and services running on each node\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Manage a pool of public IP addresses that are used to provide services to clients\&. Alternatively, CTDB can be used with LVS\&. .RE .PP Combined with a cluster filesystem CTDB provides a full high\-availablity (HA) environment for services such as clustered Samba, NFS and other services\&. .SH "ANATOMY OF A CTDB CLUSTER" .PP A CTDB cluster is a collection of nodes with 2 or more network interfaces\&. All nodes provide network (usually file/NAS) services to clients\&. Data served by file services is stored on shared storage (usually a cluster filesystem) that is accessible by all nodes\&. .PP CTDB provides an "all active" cluster, where services are load balanced across all nodes\&. .SH "PRIVATE VS PUBLIC ADDRESSES" .PP Each node in a CTDB cluster has multiple IP addresses assigned to it: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} A single private IP address that is used for communication between nodes\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} One or more public IP addresses that are used to provide NAS or other services\&. .RE .sp .SS "Private address" .PP Each node is configured with a unique, permanently assigned private address\&. This address is configured by the operating system\&. This address uniquely identifies a physical node in the cluster and is the address that CTDB daemons will use to communicate with the CTDB daemons on other nodes\&. .PP Private addresses are listed in the file specified by the \fICTDB_NODES\fR configuration variable (see \fBctdbd.conf\fR(5), default /etc/ctdb/nodes)\&. This file contains the list of private addresses for all nodes in the cluster, one per line\&. This file must be the same on all nodes in the cluster\&. .PP Private addresses should not be used by clients to connect to services provided by the cluster\&. .PP It is strongly recommended that the private addresses are configured on a private network that is separate from client networks\&. .PP Example /etc/ctdb/nodes for a four node cluster: .sp .if n \{\ .RS 4 .\} .nf 192\&.168\&.1\&.1 192\&.168\&.1\&.2 192\&.168\&.1\&.3 192\&.168\&.1\&.4 .fi .if n \{\ .RE .\} .SS "Public addresses" .PP Public addresses are used to provide services to clients\&. Public addresses are not configured at the operating system level and are not permanently associated with a particular node\&. Instead, they are managed by CTDB and are assigned to interfaces on physical nodes at runtime\&. .PP The CTDB cluster will assign/reassign these public addresses across the available healthy nodes in the cluster\&. When one node fails, its public addresses will be taken over by one or more other nodes in the cluster\&. This ensures that services provided by all public addresses are always available to clients, as long as there are nodes available capable of hosting this address\&. .PP The public address configuration is stored in a file on each node specified by the \fICTDB_PUBLIC_ADDRESSES\fR configuration variable (see \fBctdbd.conf\fR(5), recommended /etc/ctdb/public_addresses)\&. This file contains a list of the public addresses that the node is capable of hosting, one per line\&. Each entry also contains the netmask and the interface to which the address should be assigned\&. .PP Example /etc/ctdb/public_addresses for a node that can host 4 public addresses, on 2 different interfaces: .sp .if n \{\ .RS 4 .\} .nf 10\&.1\&.1\&.1/24 eth1 10\&.1\&.1\&.2/24 eth1 10\&.1\&.2\&.1/24 eth2 10\&.1\&.2\&.2/24 eth2 .fi .if n \{\ .RE .\} .PP In many cases the public addresses file will be the same on all nodes\&. However, it is possible to use different public address configurations on different nodes\&. .PP Example: 4 nodes partitioned into two subgroups: .sp .if n \{\ .RS 4 .\} .nf Node 0:/etc/ctdb/public_addresses 10\&.1\&.1\&.1/24 eth1 10\&.1\&.1\&.2/24 eth1 Node 1:/etc/ctdb/public_addresses 10\&.1\&.1\&.1/24 eth1 10\&.1\&.1\&.2/24 eth1 Node 2:/etc/ctdb/public_addresses 10\&.1\&.2\&.1/24 eth2 10\&.1\&.2\&.2/24 eth2 Node 3:/etc/ctdb/public_addresses 10\&.1\&.2\&.1/24 eth2 10\&.1\&.2\&.2/24 eth2 .fi .if n \{\ .RE .\} .PP In this example nodes 0 and 1 host two public addresses on the 10\&.1\&.1\&.x network while nodes 2 and 3 host two public addresses for the 10\&.1\&.2\&.x network\&. .PP Public address 10\&.1\&.1\&.1 can be hosted by either of nodes 0 or 1 and will be available to clients as long as at least one of these two nodes are available\&. .PP If both nodes 0 and 1 become unavailable then public address 10\&.1\&.1\&.1 also becomes unavailable\&. 10\&.1\&.1\&.1 can not be failed over to nodes 2 or 3 since these nodes do not have this public address configured\&. .PP The \fBctdb ip\fR command can be used to view the current assignment of public addresses to physical nodes\&. .SH "NODE STATUS" .PP The current status of each node in the cluster can be viewed by the \fBctdb status\fR command\&. .PP A node can be in one of the following states: .PP OK .RS 4 This node is healthy and fully functional\&. It hosts public addresses to provide services\&. .RE .PP DISCONNECTED .RS 4 This node is not reachable by other nodes via the private network\&. It is not currently participating in the cluster\&. It \fIdoes not\fR host public addresses to provide services\&. It might be shut down\&. .RE .PP DISABLED .RS 4 This node has been administratively disabled\&. This node is partially functional and participates in the cluster\&. However, it \fIdoes not\fR host public addresses to provide services\&. .RE .PP UNHEALTHY .RS 4 A service provided by this node has failed a health check and should be investigated\&. This node is partially functional and participates in the cluster\&. However, it \fIdoes not\fR host public addresses to provide services\&. Unhealthy nodes should be investigated and may require an administrative action to rectify\&. .RE .PP BANNED .RS 4 CTDB is not behaving as designed on this node\&. For example, it may have failed too many recovery attempts\&. Such nodes are banned from participating in the cluster for a configurable time period before they attempt to rejoin the cluster\&. A banned node \fIdoes not\fR host public addresses to provide services\&. All banned nodes should be investigated and may require an administrative action to rectify\&. .RE .PP STOPPED .RS 4 This node has been administratively exclude from the cluster\&. A stopped node does no participate in the cluster and \fIdoes not\fR host public addresses to provide services\&. This state can be used while performing maintenance on a node\&. .RE .PP PARTIALLYONLINE .RS 4 A node that is partially online participates in a cluster like a healthy (OK) node\&. Some interfaces to serve public addresses are down, but at least one interface is up\&. See also \fBctdb ifaces\fR\&. .RE .SH "CAPABILITIES" .PP Cluster nodes can have several different capabilities enabled\&. These are listed below\&. .PP RECMASTER .RS 4 Indicates that a node can become the CTDB cluster recovery master\&. The current recovery master is decided via an election held by all active nodes with this capability\&. .sp Default is YES\&. .RE .PP LMASTER .RS 4 Indicates that a node can be the location master (LMASTER) for database records\&. The LMASTER always knows which node has the latest copy of a record in a volatile database\&. .sp Default is YES\&. .RE .PP LVS .RS 4 Indicates that a node is configued in Linux Virtual Server (LVS) mode\&. In this mode the entire CTDB cluster uses one single public address for the entire cluster instead of using multiple public addresses in failover mode\&. This is an alternative to using a load\-balancing layer\-4 switch\&. See the LVS section for more details\&. .RE .PP NATGW .RS 4 Indicates that this node is configured to become the NAT gateway master in a NAT gateway group\&. See the NAT GATEWAY section for more details\&. .RE .PP The RECMASTER and LMASTER capabilities can be disabled when CTDB is used to create a cluster spanning across WAN links\&. In this case CTDB acts as a WAN accelerator\&. .SH "LVS" .PP LVS is a mode where CTDB presents one single IP address for the entire cluster\&. This is an alternative to using public IP addresses and round\-robin DNS to loadbalance clients across the cluster\&. .PP This is similar to using a layer\-4 loadbalancing switch but with some restrictions\&. .PP In this mode the cluster selects a set of nodes in the cluster and loadbalance all client access to the LVS address across this set of nodes\&. This set of nodes are all LVS capable nodes that are HEALTHY, or if no HEALTHY nodes exists all LVS capable nodes regardless of health status\&. LVS will however never loadbalance traffic to nodes that are BANNED, STOPPED, DISABLED or DISCONNECTED\&. The \fBctdb lvs\fR command is used to show which nodes are currently load\-balanced across\&. .PP One of the these nodes are elected as the LVSMASTER\&. This node receives all traffic from clients coming in to the LVS address and multiplexes it across the internal network to one of the nodes that LVS is using\&. When responding to the client, that node will send the data back directly to the client, bypassing the LVSMASTER node\&. The command \fBctdb lvsmaster\fR will show which node is the current LVSMASTER\&. .PP The path used for a client I/O is: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} Client sends request packet to LVSMASTER\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} LVSMASTER passes the request on to one node across the internal network\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} Selected node processes the request\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} Node responds back to client\&. .RE .PP This means that all incoming traffic to the cluster will pass through one physical node, which limits scalability\&. You can send more data to the LVS address that one physical node can multiplex\&. This means that you should not use LVS if your I/O pattern is write\-intensive since you will be limited in the available network bandwidth that node can handle\&. LVS does work wery well for read\-intensive workloads where only smallish READ requests are going through the LVSMASTER bottleneck and the majority of the traffic volume (the data in the read replies) goes straight from the processing node back to the clients\&. For read\-intensive i/o patterns you can acheive very high throughput rates in this mode\&. .PP Note: you can use LVS and public addresses at the same time\&. .PP If you use LVS, you must have a permanent address configured for the public interface on each node\&. This address must be routable and the cluster nodes must be configured so that all traffic back to client hosts are routed through this interface\&. This is also required in order to allow samba/winbind on the node to talk to the domain controller\&. This LVS IP address can not be used to initiate outgoing traffic\&. .PP Make sure that the domain controller and the clients are reachable from a node \fIbefore\fR you enable LVS\&. Also ensure that outgoing traffic to these hosts is routed out through the configured public interface\&. .SS "Configuration" .PP To activate LVS on a CTDB node you must specify the \fICTDB_PUBLIC_INTERFACE\fR and \fICTDB_LVS_PUBLIC_IP\fR configuration variables\&. Setting the latter variable also enables the LVS capability on the node at startup\&. .PP Example: .sp .if n \{\ .RS 4 .\} .nf CTDB_PUBLIC_INTERFACE=eth1 CTDB_LVS_PUBLIC_IP=10\&.1\&.1\&.237 .fi .if n \{\ .RE .\} .sp .SH "NAT GATEWAY" .PP NAT gateway (NATGW) is an optional feature that is used to configure fallback routing for nodes\&. This allows cluster nodes to connect to external services (e\&.g\&. DNS, AD, NIS and LDAP) when they do not host any public addresses (e\&.g\&. when they are unhealthy)\&. .PP This also applies to node startup because CTDB marks nodes as UNHEALTHY until they have passed a "monitor" event\&. In this context, NAT gateway helps to avoid a "chicken and egg" situation where a node needs to access an external service to become healthy\&. .PP Another way of solving this type of problem is to assign an extra static IP address to a public interface on every node\&. This is simpler but it uses an extra IP address per node, while NAT gateway generally uses only one extra IP address\&. .SS "Operation" .PP One extra NATGW public address is assigned on the public network to each NATGW group\&. Each NATGW group is a set of nodes in the cluster that shares the same NATGW address to talk to the outside world\&. Normally there would only be one NATGW group spanning an entire cluster, but in situations where one CTDB cluster spans multiple physical sites it might be useful to have one NATGW group for each site\&. .PP There can be multiple NATGW groups in a cluster but each node can only be member of one NATGW group\&. .PP In each NATGW group, one of the nodes is selected by CTDB to be the NATGW master and the other nodes are consider to be NATGW slaves\&. NATGW slaves establish a fallback default route to the NATGW master via the private network\&. When a NATGW slave hosts no public IP addresses then it will use this route for outbound connections\&. The NATGW master hosts the NATGW public IP address and routes outgoing connections from slave nodes via this IP address\&. It also establishes a fallback default route\&. .SS "Configuration" .PP NATGW is usually configured similar to the following example configuration: .sp .if n \{\ .RS 4 .\} .nf CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes CTDB_NATGW_PRIVATE_NETWORK=192\&.168\&.1\&.0/24 CTDB_NATGW_PUBLIC_IP=10\&.0\&.0\&.227/24 CTDB_NATGW_PUBLIC_IFACE=eth0 CTDB_NATGW_DEFAULT_GATEWAY=10\&.0\&.0\&.1 .fi .if n \{\ .RE .\} .PP Normally any node in a NATGW group can act as the NATGW master\&. Some configurations may have special nodes that lack connectivity to a public network\&. In such cases, \fICTDB_NATGW_SLAVE_ONLY\fR can be used to limit the NATGW functionality of thos nodes\&. .PP See the NAT GATEWAY section in \fBctdb.conf\fR(5) for more details of NATGW configuration\&. .SS "Implementation details" .PP When the NATGW functionality is used, one of the nodes is selected to act as a NAT gateway for all the other nodes in the group when they need to communicate with the external services\&. The NATGW master is selected to be a node that is most likely to have usable networks\&. .PP The NATGW master hosts the NATGW public IP address \fICTDB_NATGW_PUBLIC_IP\fR on the configured public interfaces \fICTDB_NATGW_PUBLIC_IFACE\fR and acts as a router, masquerading outgoing connections from slave nodes via this IP address\&. It also establishes a fallback default route to the configured default gateway \fICTDB_NATGW_DEFAULT_GATEWAY\fR with a metric of 10\&. A metric 10 route is used so it can co\-exist with other default routes that may be available\&. .PP A NATGW slave establishes its fallback default route to the NATGW master via the private network \fICTDB_NATGW_PRIVATE_NETWORK\fRwith a metric of 10\&. This route is used for outbound connections when no other default route is available because the node hosts no public addresses\&. A metric 10 routes is used so that it can co\-exist with other default routes that may be available when the node is hosting public addresses\&. .PP This is implemented in the 11\&.natgw eventscript\&. Please see the eventscript file for the finer details\&. .SH "POLICY ROUTING" .PP Policy routing is an optional CTDB feature to support complex network topologies\&. Public addresses may be spread across several different networks (or VLANs) and it may not be possible to route packets from these public addresses via the system\*(Aqs default route\&. Therefore, CTDB has support for policy routing via the 13\&.per_ip_routing eventscript\&. This allows routing to be specified for packets sourced from each public address\&. The routes are added and removed as CTDB moves public addresses between nodes\&. .SS "Configuration variables" .PP There are 4 configuration variables related to policy routing: \fICTDB_PER_IP_ROUTING_CONF\fR, \fICTDB_PER_IP_ROUTING_RULE_PREF\fR, \fICTDB_PER_IP_ROUTING_TABLE_ID_LOW\fR, \fICTDB_PER_IP_ROUTING_TABLE_ID_HIGH\fR\&. See the POLICY ROUTING section in \fBctdbd.conf\fR(5) for more details\&. .SS "Configuration" .PP The format of each line of \fICTDB_PER_IP_ROUTING_CONF\fR is: .sp .if n \{\ .RS 4 .\} .nf [ ] .fi .if n \{\ .RE .\} .PP Leading whitespace is ignored and arbitrary whitespace may be used as a separator\&. Lines that have a "public address" item that doesn\*(Aqt match an actual public address are ignored\&. This means that comment lines can be added using a leading character such as \*(Aq#\*(Aq, since this will never match an IP address\&. .PP A line without a gateway indicates a link local route\&. .PP For example, consider the configuration line: .sp .if n \{\ .RS 4 .\} .nf 192\&.168\&.1\&.99 192\&.168\&.1\&.1/24 .fi .if n \{\ .RE .\} .PP If the corresponding public_addresses line is: .sp .if n \{\ .RS 4 .\} .nf 192\&.168\&.1\&.99/24 eth2,eth3 .fi .if n \{\ .RE .\} .PP \fICTDB_PER_IP_ROUTING_RULE_PREF\fR is 100, and CTDB adds the address to eth2 then the following routing information is added: .sp .if n \{\ .RS 4 .\} .nf ip rule add from 192\&.168\&.1\&.99 pref 100 table ctdb\&.192\&.168\&.1\&.99 ip route add 192\&.168\&.1\&.0/24 dev eth2 table ctdb\&.192\&.168\&.1\&.99 .fi .if n \{\ .RE .\} .PP This causes traffic from 192\&.168\&.1\&.1 to 192\&.168\&.1\&.0/24 go via eth2\&. .PP The \fBip rule\fR command will show (something like \- depending on other public addresses and other routes on the system): .sp .if n \{\ .RS 4 .\} .nf 0: from all lookup local 100: from 192\&.168\&.1\&.99 lookup ctdb\&.192\&.168\&.1\&.99 32766: from all lookup main 32767: from all lookup default .fi .if n \{\ .RE .\} .PP \fBip route show table ctdb\&.192\&.168\&.1\&.99\fR will show: .sp .if n \{\ .RS 4 .\} .nf 192\&.168\&.1\&.0/24 dev eth2 scope link .fi .if n \{\ .RE .\} .PP The usual use for a line containing a gateway is to add a default route corresponding to a particular source address\&. Consider this line of configuration: .sp .if n \{\ .RS 4 .\} .nf 192\&.168\&.1\&.99 0\&.0\&.0\&.0/0 192\&.168\&.1\&.1 .fi .if n \{\ .RE .\} .PP In the situation described above this will cause an extra routing command to be executed: .sp .if n \{\ .RS 4 .\} .nf ip route add 0\&.0\&.0\&.0/0 via 192\&.168\&.1\&.1 dev eth2 table ctdb\&.192\&.168\&.1\&.99 .fi .if n \{\ .RE .\} .PP With both configuration lines, \fBip route show table ctdb\&.192\&.168\&.1\&.99\fR will show: .sp .if n \{\ .RS 4 .\} .nf 192\&.168\&.1\&.0/24 dev eth2 scope link default via 192\&.168\&.1\&.1 dev eth2 .fi .if n \{\ .RE .\} .SS "Sample configuration" .PP Here is a more complete example configuration\&. .sp .if n \{\ .RS 4 .\} .nf /etc/ctdb/public_addresses: 192\&.168\&.1\&.98 eth2,eth3 192\&.168\&.1\&.99 eth2,eth3 /etc/ctdb/policy_routing: 192\&.168\&.1\&.98 192\&.168\&.1\&.0/24 192\&.168\&.1\&.98 192\&.168\&.200\&.0/24 192\&.168\&.1\&.254 192\&.168\&.1\&.98 0\&.0\&.0\&.0/0 192\&.168\&.1\&.1 192\&.168\&.1\&.99 192\&.168\&.1\&.0/24 192\&.168\&.1\&.99 192\&.168\&.200\&.0/24 192\&.168\&.1\&.254 192\&.168\&.1\&.99 0\&.0\&.0\&.0/0 192\&.168\&.1\&.1 .fi .if n \{\ .RE .\} .PP The routes local packets as expected, the default route is as previously discussed, but packets to 192\&.168\&.200\&.0/24 are routed via the alternate gateway 192\&.168\&.1\&.254\&. .SH "NOTIFICATION SCRIPT" .PP When certain state changes occur in CTDB, it can be configured to perform arbitrary actions via a notification script\&. For example, sending SNMP traps or emails when a node becomes unhealthy or similar\&. .PP This is activated by setting the \fICTDB_NOTIFY_SCRIPT\fR configuration variable\&. The specified script must be executable\&. .PP Use of the provided /etc/ctdb/notify\&.sh script is recommended\&. It executes files in /etc/ctdb/notify\&.d/\&. .PP CTDB currently generates notifications after CTDB changes to these states: .RS 4 init .RE .RS 4 setup .RE .RS 4 startup .RE .RS 4 healthy .RE .RS 4 unhealthy .RE .SH "DEBUG LEVELS" .PP Valid values for DEBUGLEVEL are: .RS 4 EMERG (\-3) .RE .RS 4 ALERT (\-2) .RE .RS 4 CRIT (\-1) .RE .RS 4 ERR (0) .RE .RS 4 WARNING (1) .RE .RS 4 NOTICE (2) .RE .RS 4 INFO (3) .RE .RS 4 DEBUG (4) .RE .SH "REMOTE CLUSTER NODES" .PP It is possible to have a CTDB cluster that spans across a WAN link\&. For example where you have a CTDB cluster in your datacentre but you also want to have one additional CTDB node located at a remote branch site\&. This is similar to how a WAN accelerator works but with the difference that while a WAN\-accelerator often acts as a Proxy or a MitM, in the ctdb remote cluster node configuration the Samba instance at the remote site IS the genuine server, not a proxy and not a MitM, and thus provides 100% correct CIFS semantics to clients\&. .PP See the cluster as one single multihomed samba server where one of the NICs (the remote node) is very far away\&. .PP NOTE: This does require that the cluster filesystem you use can cope with WAN\-link latencies\&. Not all cluster filesystems can handle WAN\-link latencies! Whether this will provide very good WAN\-accelerator performance or it will perform very poorly depends entirely on how optimized your cluster filesystem is in handling high latency for data and metadata operations\&. .PP To activate a node as being a remote cluster node you need to set the following two parameters in /etc/sysconfig/ctdb for the remote node: .sp .if n \{\ .RS 4 .\} .nf CTDB_CAPABILITY_LMASTER=no CTDB_CAPABILITY_RECMASTER=no .fi .if n \{\ .RE .\} .PP Verify with the command "ctdb getcapabilities" that that node no longer has the recmaster or the lmaster capabilities\&. .SH "SEE ALSO" .PP \fBctdb\fR(1), \fBctdbd\fR(1), \fBctdbd_wrapper\fR(1), \fBltdbtool\fR(1), \fBonnode\fR(1), \fBping_pong\fR(1), \fBctdbd.conf\fR(5), \fBctdb-tunables\fR(7), \m[blue]\fB\%http://ctdb.samba.org/\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Ronnie Sahlberg, Amitay Isaacs, Martin Schwenke .SH "COPYRIGHT" .br Copyright \(co 2007 Andrew Tridgell, Ronnie Sahlberg .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp ctdb-2.5.1.dfsg/doc/ctdb.1.html0000644000175000017500000015100012245332457015741 0ustar mathieumathieuctdb

Name

ctdb — CTDB management utility

Synopsis

ctdb [OPTION...] {COMMAND} [COMMAND-ARGS]

DESCRIPTION

ctdb is a utility to view and manage a CTDB cluster.

The following terms are used when referring to nodes in a cluster:

PNN

Physical Node Number. The physical node number is an integer that describes the node in the cluster. The first node has physical node number 0. in a cluster.

PNN-LIST

This is either a single PNN, a comma-separate list of PNNs or "all".

Commands that reference a database have a DB argument. This is either a database name, such as locking.tdb or a database ID such as "0x42fe72c5".

OPTIONS

-n PNN-LIST

The nodes specified by PNN-LIST should be queried for the requested information. Default is to query the daemon running on the local host.

-Y

Produce output in machine readable form for easier parsing by scripts. Not all commands support this option.

-t TIMEOUT

Indicates that ctdb should wait up to TIMEOUT seconds for a response to most commands sent to the CTDB daemon. The default is 10 seconds.

-T TIMELIMIT

Indicates that TIMELIMIT is the maximum run time (in seconds) for the ctdb command. When TIMELIMIT is exceeded the ctdb command will terminate with an error. The default is 120 seconds.

-? --help

Print some help text to the screen.

--usage

Print useage information to the screen.

-d --debug=DEBUGLEVEL

Change the debug level for the command. Default is ERR (0).

--socket=FILENAME

Specify that FILENAME is the name of the Unix domain socket to use when connecting to the local CTDB daemon. The default is /tmp/ctdb.socket.

ADMINISTRATIVE COMMANDS

These are commands used to monitor and administer a CTDB cluster.

pnn

This command displays the PNN of the current node.

xpnn

This command displays the PNN of the current node without contacting the CTDB daemon. It parses the nodes file directly, so can produce unexpected output if the nodes file has been edited but has not been reloaded.

status

This command shows the current status of all CTDB nodes based on information from the queried node.

Note: If the the queried node is INACTIVE then the status might not be current.

Node status

This includes the number of physical nodes and the status of each node. See ctdb(7) for information about node states.

Generation

The generation id is a number that indicates the current generation of a cluster instance. Each time a cluster goes through a reconfiguration or a recovery its generation id will be changed.

This number does not have any particular meaning other than to keep track of when a cluster has gone through a recovery. It is a random number that represents the current instance of a ctdb cluster and its databases. The CTDB daemon uses this number internally to be able to tell when commands to operate on the cluster and the databases was issued in a different generation of the cluster, to ensure that commands that operate on the databases will not survive across a cluster database recovery. After a recovery, all old outstanding commands will automatically become invalid.

Sometimes this number will be shown as "INVALID". This only means that the ctdbd daemon has started but it has not yet merged with the cluster through a recovery. All nodes start with generation "INVALID" and are not assigned a real generation id until they have successfully been merged with a cluster through a recovery.

Virtual Node Number (VNN) map

Consists of the number of virtual nodes and mapping from virtual node numbers to physical node numbers. Virtual nodes host CTDB databases. Only nodes that are participating in the VNN map can become lmaster or dmaster for database records.

Recovery mode

This is the current recovery mode of the cluster. There are two possible modes:

NORMAL - The cluster is fully operational.

RECOVERY - The cluster databases have all been frozen, pausing all services while the cluster awaits a recovery process to complete. A recovery process should finish within seconds. If a cluster is stuck in the RECOVERY state this would indicate a cluster malfunction which needs to be investigated.

Once the recovery master detects an inconsistency, for example a node becomes disconnected/connected, the recovery daemon will trigger a cluster recovery process, where all databases are remerged across the cluster. When this process starts, the recovery master will first "freeze" all databases to prevent applications such as samba from accessing the databases and it will also mark the recovery mode as RECOVERY.

When the CTDB daemon starts up, it will start in RECOVERY mode. Once the node has been merged into a cluster and all databases have been recovered, the node mode will change into NORMAL mode and the databases will be "thawed", allowing samba to access the databases again.

Recovery master

This is the cluster node that is currently designated as the recovery master. This node is responsible of monitoring the consistency of the cluster and to perform the actual recovery process when reqired.

Only one node at a time can be the designated recovery master. Which node is designated the recovery master is decided by an election process in the recovery daemons running on each node.

Example

# ctdb status
Number of nodes:4
pnn:0 192.168.2.200       OK (THIS NODE)
pnn:1 192.168.2.201       OK
pnn:2 192.168.2.202       OK
pnn:3 192.168.2.203       OK
Generation:1362079228
Size:4
hash:0 lmaster:0
hash:1 lmaster:1
hash:2 lmaster:2
hash:3 lmaster:3
Recovery mode:NORMAL (0)
Recovery master:0
	

nodestatus [PNN-LIST]

This command is similar to the status command. It displays the "node status" subset of output. The main differences are:

  • The exit code is the bitwise-OR of the flags for each specified node, while ctdb status exits with 0 if it was able to retrieve status for all nodes.

  • ctdb status provides status information for all nodes. ctdb nodestatus defaults to providing status for only the current node. If PNN-LIST is provided then status is given for the indicated node(s).

    By default, ctdb nodestatus gathers status from the local node. However, if invoked with "-n all" (or similar) then status is gathered from the given node(s). In particular ctdb nodestatus all and ctdb nodestatus -n all will produce different output. It is possible to provide 2 different nodespecs (with and without "-n") but the output is usually confusing!

A common invocation in scripts is ctdb nodestatus all to check whether all nodes in a cluster are healthy.

Example

# ctdb nodestatus
pnn:0 10.0.0.30        OK (THIS NODE)

# ctdb nodestatus all
Number of nodes:2
pnn:0 10.0.0.30        OK (THIS NODE)
pnn:1 10.0.0.31        OK
	

recmaster

This command shows the pnn of the node which is currently the recmaster.

Note: If the the queried node is INACTIVE then the status might not be current.

uptime

This command shows the uptime for the ctdb daemon. When the last recovery or ip-failover completed and how long it took. If the "duration" is shown as a negative number, this indicates that there is a recovery/failover in progress and it started that many seconds ago.

Example

# ctdb uptime
Current time of node          :                Thu Oct 29 10:38:54 2009
Ctdbd start time              : (000 16:54:28) Wed Oct 28 17:44:26 2009
Time of last recovery/failover: (000 16:53:31) Wed Oct 28 17:45:23 2009
Duration of last recovery/failover: 2.248552 seconds
	

listnodes

This command shows lists the ip addresses of all the nodes in the cluster.

Example

# ctdb listnodes
192.168.2.200
192.168.2.201
192.168.2.202
192.168.2.203
	

natgwlist

Show the current NAT gateway master and the status of all nodes in the current NAT gateway group. See the NAT GATEWAY section in ctdb(7) for more details.

Example

# ctdb natgwlist
0 192.168.2.200
Number of nodes:4
pnn:0 192.168.2.200       OK (THIS NODE)
pnn:1 192.168.2.201       OK
pnn:2 192.168.2.202       OK
pnn:3 192.168.2.203       OK
	

ping

This command will "ping" specified CTDB nodes in the cluster to verify that they are running.

Example

# ctdb ping -n all
response from 0 time=0.000054 sec  (3 clients)
response from 1 time=0.000144 sec  (2 clients)
response from 2 time=0.000105 sec  (2 clients)
response from 3 time=0.000114 sec  (2 clients)
	

ifaces

This command will display the list of network interfaces, which could host public addresses, along with their status.

Example

# ctdb ifaces
Interfaces on node 0
name:eth5 link:up references:2
name:eth4 link:down references:0
name:eth3 link:up references:1
name:eth2 link:up references:1

# ctdb ifaces -Y
:Name:LinkStatus:References:
:eth5:1:2
:eth4:0:0
:eth3:1:1
:eth2:1:1
	

ip

This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip. By default this command will ONLY show those public addresses that are known to the node itself. To see the full list of all public ips across the cluster you must use "ctdb ip -n all".

Example

# ctdb ip
Public IPs on node 0
172.31.91.82 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
172.31.91.83 node[0] active[eth3] available[eth2,eth3] configured[eth2,eth3]
172.31.91.84 node[1] active[] available[eth2,eth3] configured[eth2,eth3]
172.31.91.85 node[0] active[eth2] available[eth2,eth3] configured[eth2,eth3]
172.31.92.82 node[1] active[] available[eth5] configured[eth4,eth5]
172.31.92.83 node[0] active[eth5] available[eth5] configured[eth4,eth5]
172.31.92.84 node[1] active[] available[eth5] configured[eth4,eth5]
172.31.92.85 node[0] active[eth5] available[eth5] configured[eth4,eth5]

# ctdb ip -Y
:Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:
:172.31.91.82:1::eth2,eth3:eth2,eth3:
:172.31.91.83:0:eth3:eth2,eth3:eth2,eth3:
:172.31.91.84:1::eth2,eth3:eth2,eth3:
:172.31.91.85:0:eth2:eth2,eth3:eth2,eth3:
:172.31.92.82:1::eth5:eth4,eth5:
:172.31.92.83:0:eth5:eth5:eth4,eth5:
:172.31.92.84:1::eth5:eth4,eth5:
:172.31.92.85:0:eth5:eth5:eth4,eth5:
	

ipinfo IP

This command will display details about the specified public addresses.

Example

# ctdb ipinfo 172.31.92.85
Public IP[172.31.92.85] info on node 0
IP:172.31.92.85
CurrentNode:0
NumInterfaces:2
Interface[1]: Name:eth4 Link:down References:0
Interface[2]: Name:eth5 Link:up References:2 (active)
	

scriptstatus

This command displays which scripts where run in the previous monitoring cycle and the result of each script. If a script failed with an error, causing the node to become unhealthy, the output from that script is also shown.

Example

# ctdb scriptstatus
7 scripts were executed last monitoring cycle
00.ctdb              Status:OK    Duration:0.056 Tue Mar 24 18:56:57 2009
10.interface         Status:OK    Duration:0.077 Tue Mar 24 18:56:57 2009
11.natgw             Status:OK    Duration:0.039 Tue Mar 24 18:56:57 2009
20.multipathd        Status:OK    Duration:0.038 Tue Mar 24 18:56:57 2009
31.clamd             Status:DISABLED
40.vsftpd            Status:OK    Duration:0.045 Tue Mar 24 18:56:57 2009
41.httpd             Status:OK    Duration:0.039 Tue Mar 24 18:56:57 2009
50.samba             Status:ERROR    Duration:0.082 Tue Mar 24 18:56:57 2009
OUTPUT:ERROR: Samba tcp port 445 is not responding
      

disablescript SCRIPT

This command is used to disable an eventscript.

This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'.

enablescript SCRIPT

This command is used to enable an eventscript.

This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'.

listvars

List all tuneable variables, except the values of the obsolete tunables like VacuumMinInterval. The obsolete tunables can be retrieved only explicitly with the "ctdb getvar" command.

Example

# ctdb listvars
MaxRedirectCount        = 3
SeqnumInterval          = 1000
ControlTimeout          = 60
TraverseTimeout         = 20
KeepaliveInterval       = 5
KeepaliveLimit          = 5
RecoverTimeout          = 20
RecoverInterval         = 1
ElectionTimeout         = 3
TakeoverTimeout         = 9
MonitorInterval         = 15
TickleUpdateInterval    = 20
EventScriptTimeout      = 30
EventScriptTimeoutCount = 1
RecoveryGracePeriod     = 120
RecoveryBanPeriod       = 300
DatabaseHashSize        = 100001
DatabaseMaxDead         = 5
RerecoveryTimeout       = 10
EnableBans              = 1
DeterministicIPs        = 0
LCP2PublicIPs           = 1
ReclockPingPeriod       = 60
NoIPFailback            = 0
DisableIPFailover       = 0
VerboseMemoryNames      = 0
RecdPingTimeout         = 60
RecdFailCount           = 10
LogLatencyMs            = 0
RecLockLatencyMs        = 1000
RecoveryDropAllIPs      = 120
VerifyRecoveryLock      = 1
VacuumInterval          = 10
VacuumMaxRunTime        = 30
RepackLimit             = 10000
VacuumLimit             = 5000
VacuumFastPathCount     = 60
MaxQueueDropMsg         = 1000000
UseStatusEvents         = 0
AllowUnhealthyDBRead    = 0
StatHistoryInterval     = 1
DeferredAttachTO        = 120
AllowClientDBAttach     = 1
RecoverPDBBySeqNum      = 0
	

getvar NAME

Get the runtime value of a tuneable variable.

Example

# ctdb getvar MaxRedirectCount
MaxRedirectCount    = 3
	

setvar NAME VALUE

Set the runtime value of a tuneable variable.

Example: ctdb setvar MaxRedirectCount 5

lvsmaster

This command shows which node is currently the LVSMASTER. The LVSMASTER is the node in the cluster which drives the LVS system and which receives all incoming traffic from clients.

LVS is the mode where the entire CTDB/Samba cluster uses a single ip address for the entire cluster. In this mode all clients connect to one specific node which will then multiplex/loadbalance the clients evenly onto the other nodes in the cluster. This is an alternative to using public ip addresses. See the manpage for ctdbd for more information about LVS.

lvs

This command shows which nodes in the cluster are currently active in the LVS configuration. I.e. which nodes we are currently loadbalancing the single ip address across.

LVS will by default only loadbalance across those nodes that are both LVS capable and also HEALTHY. Except if all nodes are UNHEALTHY in which case LVS will loadbalance across all UNHEALTHY nodes as well. LVS will never use nodes that are DISCONNECTED, STOPPED, BANNED or DISABLED.

Example output:

2:10.0.0.13
3:10.0.0.14
      

getcapabilities

This command shows the capabilities of the current node. See the CAPABILITIES section in ctdb(7) for more details.

Example output:

RECMASTER: YES
LMASTER: YES
LVS: NO
NATGW: YES
      

statistics

Collect statistics from the CTDB daemon about how many calls it has served.

Example

# ctdb statistics
CTDB version 1
num_clients                        3
frozen                             0
recovering                         0
client_packets_sent           360489
client_packets_recv           360466
node_packets_sent             480931
node_packets_recv             240120
keepalive_packets_sent             4
keepalive_packets_recv             3
node
req_call                       2
reply_call                     2
req_dmaster                    0
reply_dmaster                  0
reply_error                    0
req_message                   42
req_control               120408
reply_control             360439
client
req_call                       2
req_message                   24
req_control               360440
timeouts
call                           0
control                        0
traverse                       0
total_calls                        2
pending_calls                      0
lockwait_calls                     0
pending_lockwait_calls             0
memory_used                     5040
max_hop_count                      0
max_call_latency                   4.948321 sec
max_lockwait_latency               0.000000 sec
	

statisticsreset

This command is used to clear all statistics counters in a node.

Example: ctdb statisticsreset

dbstatistics DB

Display statistics about the database DB.

Example

# ctdb dbstatistics locking.tdb
DB Statistics: locking.tdb
 ro_delegations                     0
 ro_revokes                         0
 locks
     total                      14356
     failed                         0
     current                        0
     pending                        0
 hop_count_buckets: 28087 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0
 lock_buckets: 0 14188 38 76 32 19 3 0 0 0 0 0 0 0 0 0
 locks_latency      MIN/AVG/MAX     0.001066/0.012686/4.202292 sec out of 14356
 Num Hot Keys:     1
     Count:8 Key:ff5bd7cb3ee3822edc1f0000000000000000000000000000
	

getreclock

This command is used to show the filename of the reclock file that is used.

Example output:

	Reclock file:/gpfs/.ctdb/shared
      

setreclock [filename]

This command is used to modify, or clear, the file that is used as the reclock file at runtime. When this command is used, the reclock file checks are disabled. To re-enable the checks the administrator needs to activate the "VerifyRecoveryLock" tunable using "ctdb setvar".

If run with no parameter this will remove the reclock file completely. If run with a parameter the parameter specifies the new filename to use for the recovery lock.

This command only affects the runtime settings of a ctdb node and will be lost when ctdb is restarted. For persistent changes to the reclock file setting you must edit /etc/sysconfig/ctdb.

getdebug

Get the current debug level for the node. the debug level controls what information is written to the log file.

The debug levels are mapped to the corresponding syslog levels. When a debug level is set, only those messages at that level and higher levels will be printed.

The list of debug levels from highest to lowest are :

EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG

setdebug DEBUGLEVEL

Set the debug level of a node. This controls what information will be logged.

The debuglevel is one of EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG

getpid

This command will return the process id of the ctdb daemon.

disable

This command is used to administratively disable a node in the cluster. A disabled node will still participate in the cluster and host clustered TDB records but its public ip address has been taken over by a different node and it no longer hosts any services.

enable

Re-enable a node that has been administratively disabled.

stop

This command is used to administratively STOP a node in the cluster. A STOPPED node is connected to the cluster but will not host any public ip addresse, nor does it participate in the VNNMAP. The difference between a DISABLED node and a STOPPED node is that a STOPPED node does not host any parts of the database which means that a recovery is required to stop/continue nodes.

continue

Re-start a node that has been administratively stopped.

addip IPADDR/mask IFACE

This command is used to add a new public ip to a node during runtime. This allows public addresses to be added to a cluster without having to restart the ctdb daemons.

Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read. If you want this change to be permanent you must also update the public addresses file manually.

delip IPADDR

This command is used to remove a public ip from a node during runtime. If this public ip is currently hosted by the node it being removed from, the ip will first be failed over to another node, if possible, before it is removed.

Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read. If you want this change to be permanent you must also update the public addresses file manually.

moveip IPADDR PNN

This command can be used to manually fail a public ip address to a specific node.

In order to manually override the "automatic" distribution of public ip addresses that ctdb normally provides, this command only works when you have changed the tunables for the daemon to:

DeterministicIPs = 0

NoIPFailback = 1

shutdown

This command will shutdown a specific CTDB daemon.

setlmasterrole on|off

This command is used ot enable/disable the LMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an LMASTER for records in the database. A node that does not have the LMASTER capability will not show up in the vnnmap.

Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command.

Once this setting has been enabled/disabled, you need to perform a recovery for it to take effect.

See also "ctdb getcapabilities"

setrecmasterrole on|off

This command is used ot enable/disable the RECMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an RECMASTER for the cluster. A node that does not have the RECMASTER capability can not win a recmaster election. A node that already is the recmaster for the cluster when the capability is stripped off the node will remain the recmaster until the next cluster election.

Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command.

See also "ctdb getcapabilities"

reloadnodes

This command is used when adding new nodes, or removing existing nodes from an existing cluster.

Procedure to add a node:

1, To expand an existing cluster, first ensure with 'ctdb status' that all nodes are up and running and that they are all healthy. Do not try to expand a cluster unless it is completely healthy!

2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last entry to the file. The new node MUST be added to the end of this file!

3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node!

4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.

5, Use 'ctdb status' on all nodes and verify that they now show the additional node.

6, Install and configure the new node and bring it online.

Procedure to remove a node:

1, To remove a node from an existing cluster, first ensure with 'ctdb status' that all nodes, except the node to be deleted, are up and running and that they are all healthy. Do not try to remove a node from a cluster unless the cluster is completely healthy!

2, Shutdown and poweroff the node to be removed.

3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed. Do not delete the line for that node, just comment it out by adding a '#' at the beginning of the line.

4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile.

5, Use 'ctdb status' on all nodes and verify that the deleted node no longer shows up in the list..

reloadips [PNN-LIST]

This command reloads the public addresses configuration file on the specified nodes. When it completes addresses will be reconfigured and reassigned across the cluster as necessary.

getdbmap

This command lists all clustered TDB databases that the CTDB daemon has attached to. Some databases are flagged as PERSISTENT, this means that the database stores data persistently and the data will remain across reboots. One example of such a database is secrets.tdb where information about how the cluster was joined to the domain is stored.

If a PERSISTENT database is not in a healthy state the database is flagged as UNHEALTHY. If there's at least one completely healthy node running in the cluster, it's possible that the content is restored by a recovery run automaticly. Otherwise an administrator needs to analyze the problem.

See also "ctdb getdbstatus", "ctdb backupdb", "ctdb restoredb", "ctdb dumpbackup", "ctdb wipedb", "ctdb setvar AllowUnhealthyDBRead 1" and (if samba or tdb-utils are installed) "tdbtool check".

Most databases are not persistent and only store the state information that the currently running samba daemons need. These databases are always wiped when ctdb/samba starts and when a node is rebooted.

Example

# ctdb getdbmap
Number of databases:10
dbid:0x435d3410 name:notify.tdb path:/var/ctdb/notify.tdb.0 
dbid:0x42fe72c5 name:locking.tdb path:/var/ctdb/locking.tdb.0
dbid:0x1421fb78 name:brlock.tdb path:/var/ctdb/brlock.tdb.0 
dbid:0x17055d90 name:connections.tdb path:/var/ctdb/connections.tdb.0 
dbid:0xc0bdde6a name:sessionid.tdb path:/var/ctdb/sessionid.tdb.0 
dbid:0x122224da name:test.tdb path:/var/ctdb/test.tdb.0 
dbid:0x2672a57f name:idmap2.tdb path:/var/ctdb/persistent/idmap2.tdb.0 PERSISTENT
dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT
dbid:0xe98e08b6 name:group_mapping.tdb path:/var/ctdb/persistent/group_mapping.tdb.0 PERSISTENT
dbid:0x7bbbd26c name:passdb.tdb path:/var/ctdb/persistent/passdb.tdb.0 PERSISTENT

# ctdb getdbmap  # example for unhealthy database
Number of databases:1
dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT UNHEALTHY

# ctdb -Y getdbmap
:ID:Name:Path:Persistent:Unhealthy:
:0x7bbbd26c:passdb.tdb:/var/ctdb/persistent/passdb.tdb.0:1:0:
	

backupdb DB FILE

Copy the contents of database DB to FILE. FILE can later be read back using restoredb. This is mainly useful for backing up persistent databases such as secrets.tdb and similar.

restoredb FILE [DB]

This command restores a persistent database that was previously backed up using backupdb. By default the data will be restored back into the same database as it was created from. By specifying dbname you can restore the data into a different database.

getlog [LEVEL] [recoverd]

In addition to the normal logging to a log file, CTDB also keeps a in-memory ringbuffer containing the most recent log entries for all log levels (except DEBUG).

This is useful since it allows for keeping continuous logs to a file at a reasonable non-verbose level, but shortly after an incident has occured, a much more detailed log can be pulled from memory. This can allow you to avoid having to reproduce an issue due to the on-disk logs being of insufficient detail.

This command extracts all messages of level or lower log level from memory and prints it to the screen. The level is not specified it defaults to NOTICE.

By default, logs are extracted from the main CTDB daemon. If the recoverd option is given then logs are extracted from the recovery daemon.

clearlog [recoverd]

This command clears the in-memory logging ringbuffer.

By default, logs are cleared in the main CTDB daemon. If the recoverd option is given then logs are cleared in the recovery daemon.

setdbreadonly DB

This command will enable the read-only record support for a database. This is an experimental feature to improve performance for contended records primarily in locking.tdb and brlock.tdb. When enabling this feature you must set it on all nodes in the cluster.

setdbsticky DB

This command will enable the sticky record support for the specified database. This is an experimental feature to improve performance for contended records primarily in locking.tdb and brlock.tdb. When enabling this feature you must set it on all nodes in the cluster.

INTERNAL COMMANDS

Internal commands are used by CTDB's scripts and are not required for managing a CTDB cluster. Their parameters and behaviour are subject to change.

gettickles IPADDR

Show TCP connections that are registered with CTDB to be "tickled" if there is a failover.

gratiousarp IPADDR INTERFACE

Send out a gratious ARP for the specified interface through the specified interface. This command is mainly used by the ctdb eventscripts.

killtcp

Read a list of TCP connections, one per line, from standard input and terminate each connection. A connection is specified as:

	SRC-IPADDR:SRC-PORT DST-IPADDR:DST-PORT
      

Each connection is terminated by issuing a TCP RST to the SRC-IPADDR:SRC-PORT endpoint.

A single connection can be specified on the command-line rather than on standard input.

pdelete DB KEY

Delete KEY from DB.

pfetch DB KEY

Print the value associated with KEY in DB.

pstore DB KEY FILE

Store KEY in DB with contents of FILE as the associated value.

ptrans DB [FILE]

Read a list of key-value pairs, one per line from FILE, and store them in DB using a single transaction. An empty value is equivalent to deleting the given key.

The key and value should be separated by spaces or tabs. Each key/value should be a printable string enclosed in double-quotes.

runstate [setup|first_recovery|startup|running]

Print the runstate of the specified node. Runstates are used to serialise important state transitions in CTDB, particularly during startup.

If one or more optional runstate arguments are specified then the node must be in one of these runstates for the command to succeed.

Example

# ctdb runstate
RUNNING
	

setifacelink IFACE up|down

Set the internal state of network interface IFACE. This is typically used in the 10.interface script in the "monitor" event.

Example: ctdb setifacelink eth0 up

setnatgwstate on|off

Enable or disable the NAT gateway master capability on a node.

tickle SRC-IPADDR:SRC-PORT DST-IPADDR:DST-PORT

Send a TCP tickle to the source host for the specified TCP connection. A TCP tickle is a TCP ACK packet with an invalid sequence and acknowledge number and will when received by the source host result in it sending an immediate correct ACK back to the other end.

TCP tickles are useful to "tickle" clients after a IP failover has occured since this will make the client immediately recognize the TCP connection has been disrupted and that the client will need to reestablish. This greatly speeds up the time it takes for a client to detect and reestablish after an IP failover in the ctdb cluster.

version

Display the CTDB version.

DEBUGGING COMMANDS

These commands are primarily used for CTDB development and testing and should not be used for normal administration.

OPTIONS

--print-emptyrecords

This enables printing of empty records when dumping databases with the catdb, cattbd and dumpdbbackup commands. Records with empty data segment are considered deleted by ctdb and cleaned by the vacuuming mechanism, so this switch can come in handy for debugging the vacuuming behaviour.

--print-datasize

This lets database dumps (catdb, cattdb, dumpdbbackup) print the size of the record data instead of dumping the data contents.

--print-lmaster

This lets catdb print the lmaster for each record.

--print-hash

This lets database dumps (catdb, cattdb, dumpdbbackup) print the hash for each record.

--print-recordflags

This lets catdb and dumpdbbackup print the record flags for each record. Note that cattdb always prints the flags.

process-exists PID

This command checks if a specific process exists on the CTDB host. This is mainly used by Samba to check if remote instances of samba are still running or not.

getdbstatus DB

This command displays more details about a database.

Example

# ctdb getdbstatus test.tdb.0
dbid: 0x122224da
name: test.tdb
path: /var/ctdb/test.tdb.0
PERSISTENT: no
HEALTH: OK

# ctdb getdbstatus registry.tdb  # with a corrupted TDB
dbid: 0xf2a58948
name: registry.tdb
path: /var/ctdb/persistent/registry.tdb.0
PERSISTENT: yes
HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persistent/registry.tdb.0.corrupted.20091208091949.0Z'
	

catdb DB

Print a dump of the clustered TDB database DB.

cattdb DB

Print a dump of the contents of the local TDB database DB.

dumpdbbackup FILE

Print a dump of the contents from database backup FILE, similar to catdb.

wipedb DB

Remove all contents of database DB.

recover

This command will trigger the recovery daemon to do a cluster recovery.

ipreallocate, sync

This command will force the recovery master to perform a full ip reallocation process and redistribute all ip addresses. This is useful to "reset" the allocations back to its default state if they have been changed using the "moveip" command. While a "recover" will also perform this reallocation, a recovery is much more hevyweight since it will also rebuild all the databases.

getmonmode

This command returns the monutoring mode of a node. The monitoring mode is either ACTIVE or DISABLED. Normally a node will continuously monitor that all other nodes that are expected are in fact connected and that they respond to commands.

ACTIVE - This is the normal mode. The node is actively monitoring all other nodes, both that the transport is connected and also that the node responds to commands. If a node becomes unavailable, it will be marked as DISCONNECTED and a recovery is initiated to restore the cluster.

DISABLED - This node is not monitoring that other nodes are available. In this mode a node failure will not be detected and no recovery will be performed. This mode is useful when for debugging purposes one wants to attach GDB to a ctdb process but wants to prevent the rest of the cluster from marking this node as DISCONNECTED and do a recovery.

setmonmode 0|1

This command can be used to explicitly disable/enable monitoring mode on a node. The main purpose is if one wants to attach GDB to a running ctdb daemon but wants to prevent the other nodes from marking it as DISCONNECTED and issuing a recovery. To do this, set monitoring mode to 0 on all nodes before attaching with GDB. Remember to set monitoring mode back to 1 afterwards.

attach DBNAME [persistent]

This is a debugging command. This command will make the CTDB daemon create a new CTDB database and attach to it.

dumpmemory

This is a debugging command. This command will make the ctdb daemon to write a fill memory allocation map to standard output.

rddumpmemory

This is a debugging command. This command will dump the talloc memory allocation tree for the recovery daemon to standard output.

thaw

Thaw a previously frozen node.

eventscript ARGUMENTS

This is a debugging command. This command can be used to manually invoke and run the eventscritps with arbitrary arguments.

ban BANTIME

Administratively ban a node for BANTIME seconds. The node will be unbanned after BANTIME seconds have elapsed.

A banned node does not participate in the cluster. It does not host any records for the clustered TDB and does not host any public IP addresses.

Nodes are automatically banned if they misbehave. For example, a node may be banned if it causes too many cluster recoveries.

To administratively exclude a node from a cluster use the stop command.

unban

This command is used to unban a node that has either been administratively banned using the ban command or has been automatically banned.

rebalancenode [PNN-LIST]

This command marks the given nodes as rebalance targets in the LCP2 IP allocation algorithm. The reloadips command will do this as necessary so this command should not be needed.

check_srvids SRVID ...

This command checks whether a set of srvid message ports are registered on the node or not. The command takes a list of values to check.

Example

# ctdb check_srvids 1 2 3 14765
Server id 0:1 does not exist
Server id 0:2 does not exist
Server id 0:3 does not exist
Server id 0:14765 exists
	

vacuum [max-records]

Over time CTDB databases will fill up with empty deleted records which will lead to a progressive slow down of CTDB database access. This command is used to prune all databases and delete all empty records from the cluster.

By default, vacuum will delete all empty records from all databases. If [max_records] is specified, the command will only delete the first [max_records] empty records for each database.

Vacuum only deletes records where the local node is the lmaster. To delete all records from the entire cluster you need to run a vacuum from each node. This command is not disruptive. Samba is unaffected and will still be able to read/write records normally while the database is being vacuumed.

Example: ctdb vacuum

By default, this operation is issued from the 00.ctdb event script every 5 minutes.

repack [max_freelist]

Over time, when records are created and deleted in a TDB, the TDB list of free space will become fragmented. This can lead to a slowdown in accessing TDB records. This command is used to defragment a TDB database and pruning the freelist.

If [max_freelist] is specified, then a database will only be repacked if it has more than this number of entries in the freelist.

During repacking of the database, the entire TDB database will be locked to prevent writes. If samba tries to write to a record in the database during a repack operation, samba will block until the repacking has completed.

This command can be disruptive and can cause samba to block for the duration of the repack operation. In general, a repack operation will take less than one second to complete.

A repack operation will only defragment the local TDB copy of the CTDB database. You need to run this command on all of the nodes to repack a CTDB database completely.

Example: ctdb repack 1000

By default, this operation is issued from the 00.ctdb event script every 5 minutes.

SEE ALSO

ctdbd(1), onnode(1), ctdb(7), ctdb-tunables(7), http://ctdb.samba.org/

ctdb-2.5.1.dfsg/doc/readonlyrecords.txt0000644000175000017500000003572512245023514017746 0ustar mathieumathieuRead-Only locks in CTDB ======================= Problem ======= CTDB currently only supports exclusive Read-Write locks for clients(samba) accessing the TDB databases. This mostly works well but when very many clients are accessing the same file, at the same time, this causes the exclusive lock as well as the record itself to rapidly bounce between nodes and acts as a scalability limitation. This primarily affects locking.tdb and brlock.tdb, two databases where record access is read-mostly and where writes are semi-rare. For the common case, if CTDB provided shared non-exlusive Read-Only lock semantincs this would greatly improve scaling for these workloads. Desired properties ================== We can not make backward incompatible changes the ctdb_ltdb header for the records. A Read-Only lock enabled ctdb demon must be able to interoperate with a non-Read-Only lock enbled daemon. Getting a Read-Only lock should not be slower than getting a Read-Write lock. When revoking Read-Only locks for a record, this should involve only those nodes that currently hold a Read-Only lock and should avoid broadcasting opportunistic revocations. (must track which nodes are delegated to) When a Read-Write lock is requested, if there are Read-Only locks delegated to other nodes, the DMASTER will defer the record migration until all read-only locks are first revoked (synchronous revoke). Due to the cost of revoking Read-Only locks has on getting a Read-Write lock, the implementation should try to avoid creating Read-Only locks unless it has indication that there is contention. This may mean that even if client requests a Read-Only lock we might still provide a full Read-Write lock in order to avoid the cost of revoking the locks in some cases. Read-Only locks require additional state to be stored in a separate database, containing information about which nodes have have been delegated Read-Only locks. This database should be kept at minimal size. Read-Only locks should not significantly complicate the normal record create/migration/deletion cycle for normal records. Read-Only locks should not complicate the recovery process. Read-Only locks should not complicate the vacuuming process. We should avoid forking new child processes as far as possible from the main daemon. Client-side implementation, samba, libctdb, others, should have minimal impact when Read-Only locks are implemented. Client-side implementation must be possible with only minor conditionals added to the existing lock-check-fetch-unlock loop that clients use today for Read-Write locks. So that clients only need one single loop that can handle both Read-Write locking as well as Read-Only locking. Clients should not need two nearly identical loops. Implementation ============== Four new flags are allocated in the ctdb_ltdb record header. HAVE_DELEGATIONS, HAVE_READONLY_LOCK, REVOKING_READONLY and REVOKE_COMPLETE HAVE_DELEGATIONS is a flag that can only be set on the node that is currently the DMASTER for the record. When set, this flag indicates that there are Read-Only locks delegated to other nodes in the cluster for this record. HAVE_READONLY is a flag that is only set on nodes that are NOT the DMASTER for the record. If set this flag indicates that this record contains an up-to-date Read-Only version of this record. A client that only needs to read, but not to write, the record can safely use the content of this record as is regardless of the value of the DMASTER field of the record. REVOKING_READONLY is a flag that is used while a set of read only delegations are being revoked. This flag is only set when HAVE_DELEGATIONS is also set, and is cleared at the same time as HAVE_DELEGATIONS is cleared. Normal operations is that first the HAVE_DELEGATIONS flag is set when the first delegation is generated. When the delegations are about to be revoked, the REVOKING_READONLY flag is set too. Once all delegations are revoked, both flags are cleared at the same time. While REVOKING_READONLY is set, any requests for the record, either normal request or request for readonly will be deferred. Deferred requests are linked on a list for deferred requests until the time that the revokation is completed. This flags is set by the main ctdb daemon when it starts revoking this record. REVOKE_COMPLETE The actual revoke of records is done by a child process, spawned from the main ctdb daemon when it starts the process to revoke the records. Once the child process has finished revoking all delegations it will set the flag REVOKE_COMPLETE for this record to signal to the main daemon that the record has been successfully revoked. At this stage the child process will also trigger an event in the main daemon that revoke is complete and that the main dameon should start re-processing all deferred requests. Once the revoke process is completed there will be at least one deferred request to access this record. That is the initical call to for an exclusive fetch_lock() that triggered the revoke process to be started. In addition to this deferred request there may also be additional requests that have also become deferred while the revoke was in process. These can be either exclusive fetch_locks() or they can be readonly lock requests. Once the revoke is completed the main daemon will reprocess all exclusive fetch_lock() requests immediately and respond to these clients. Any requests for readadonly lock requests will be deferred for an additional period of time before they are re-processed. This is to allow the client that needs a fetch_lock() to update the record to get some time to access and work on the record without having to compete with the possibly very many readonly requests. The ctdb_db structure is expanded so that it contains one extra TDB database for each normal, non-persistent datbase. This new database is used for tracking delegations for the records. A record in the normal database that has "HAVE_DELEGATION" set will always have a corresponding record at the same key. This record contains the set of all nodes that the record is delegated to. This tracking database is lockless, using TDB_NOLOCK, and is only ever accessed by the main ctdbd daemon. The lockless nature and the fact that no other process ever access this TDB means we are guaranteed non-blocking access to records in the tracking database. The ctdb_call PDU is allocated with a new flag WANT_READONLY and possibly also a new callid: CTDB_FETCH_WITH_HEADER_FUNC. This new function returns not only the record, as CTDB_FETCH_FUNC does, but also returns the full ctdb_ltdb record HEADER prepended to the record. This function is optional, clients that do not care what the header is can continue using just CTDB_FETCH_FUNC This flag is used to requesting a read-only record from the DMASTER/LMASTER. If the record does not yet exist, this is a returned as an error to the client and the client will retry the request loop. A new control is added to make remote nodes remove the HAVE_READONLY_LOCK from a record and to invalidate any deferred readonly copies from the databases. Client implementation ===================== Clients today use a loop for record fetch lock that looks like this try_again: lock record in tdb if record does not exist in tdb, unlock record ask ctdb to migrate record onto the node goto try_again if record dmaster != this node pnn unlock record ask ctdb to migrate record onto the node goto try_again finished: where we basically spin, until the record is migrated onto the node and we have managed to pin it down. This will change to instead to something like try_again: lock record in tdb if record does not exist in tdb, unlock record ask ctdb to migrate record onto the node goto try_again if record dmaster == current node pnn goto finished if read-only lock if HAVE_READONLY_LOCK or HAVE_DELEGATIONS is set goto finished else unlock record ask ctdb for read-only copy (WANT_READONLY[|WITH_HEADER]) if failed to get read-only copy (*A) ask ctdb to migrate the record onto the node goto try_again lock record in tdb goto finished unlock record ask ctdb to migrate record onto the node goto try_again finished: If the record does not yet exist in the local TDB, we always perform a full fetch for a Read-Write lock even if only a Read-Only lock was requested. This means that for first access we always grab a Read-Write lock and thus upgrade any requests for Read-Only locks into a Read-Write request. This creates the record, migrates it onto the node and makes the local node become the DMASTER for the record. Future reference to this same record by the local samba daemons will still access/lock the record locally without triggereing a Read-Only delegation to be created since the record is already hosted on the local node as DMASTER. Only if the record is contended, i.e. it has been created an migrated onto the node but we are no longer the DMASTER for this record, only for this case will we create a Read-Only delegation. This heuristics provide a mechanism where we will not create Read-Only delegations until we have some indication that the record may be contended. This avoids creating and revoking Read-Only delegations when only a single client is repeatedly accessing the same set of records. This also aims to limit the size of the tracking tdb. Server implementation ===================== When receiving a ctdb_call with the WANT_READONLY flag: If this is the LMASTER for the record and the record does not yet exist, LMASTER will return an error back to the client (*A above) and the client will try to recover. In particular, LMASTER will not create a new record for this case. If this is the LMASTER for the record and the record exists, the PDU will be forwarded to the DMASTER for the record. If this node is not the DMASTER for this record, we forward the PDU back to the LMASTER. Just as we always do today. If this is the DMASTER for the record, we need to create a Read-Only delegation. This is done by lock record increase the RSN by one for this record set the HAVE_DELEGATIONS flag for the record write the updated record to the TDB create/update the tracking TDB nd add this new node to the set of delegations send a modified copy of the record back to the requesting client. modifications are that RSN is decremented by one, so delegated records are "older" than on the DMASTER, it has HAVE_DELEGATIONS flag stripped off, and has HAVE_READONLY_LOCK added. unlock record Important to note is that this does not trigger a record migration. When receiving a ctdb_call without the WANT_READONLY flag: If this is the DMASTER for the this might trigger a migration. If there exists delegations we must first revoke these before allowing the Read-Write request from proceeding. So, IF the record has HAVE_DELEGATIONS set, we create a child process and defer processing of this PDU until the child process has completed. From the child process we will call out to all nodes that have delegations for this record and tell them to invalidate this record by clearing the HAVE_READONLY_LOCK from the record. Once all delegated nodes respond back, the child process signals back to the main daemon the revoke has completed. (child process may not access the tracking tdb since it is lockless) Main process is triggered to re-process the PDU once the child process has finished. Main daemon deletes the corresponding record in the tracking database, clears the HAVE_DELEGATIONS flag for the record and then proceeds to perform the migration as usual. When receiving a ctdb_call without the flag we want all delegations to be revoked, so we must take care that the delegations are revoked unconditionally before we even check if we are already the DMASTER (in which case thie ctdb_call would normally just be no-op (*B below)) Recovery process changes ======================== A recovery implicitly clears/revokes any read only records and delegations from all databases. During delegations of Read-Only locks, this is done in such way that delegated records will have a RSN smaller than the DMASTER. This guarantees that read-only copies always have a RSN that is smaller than the DMASTER. During recoveries we do not need to take any special action other than always picking the copy of the record that has the highest RSN, which is what we already do today. During the recovery process, we strip all flags off all records while writing the new content of the database during the PUSH_DB control. During processing of the PUSH_DB control and once the new database has been written we then also wipe the tracking database. This makes changes to the recovery process minimal and nonintrusive. Vacuuming process ================= Vacuuming needs only minimal changes. When vacuuming runs, it will do a fetch_lock to migrate any remote records back onto the LMASTER before the record can be purged. This will automatically force all delegations for that record to be revoked before the migration is copied back onto the LMASTER. This handles the case where LMASTER is not the DMASTER for the record that will be purged. The migration in this case does force any delegations to be revoked before the vacuuming takes place. Missing is the case when delegations exist and the LMASTER is also the DMASTER. For this case we need to change the vacuuming to unconditionally always try to do a fetch_lock when HAVE_DELEGATIONS is set, even if the record is already stored locally. (*B) This fetch lock will not cause any migrations by the ctdb daemon, but since it does not have the WANT_READONLY this will still force the delegations to be revoked but no migration will trigger. Traversal process ================= Traversal process is changed to ignore any records with the HAVE_READONLY_LOCK Forward/Backward Compatibility ============================== Non-readonly locking daemons must be able to interoperate with readonly locking enabled daemons. Non-readonly enabled daemons fetching records from Readonly enabled daemons: Non-readonly enabled daemons do not know, and never set the WANT_READONLY flag so these daemons will always request a full migration for a full fetch-lock for all records. Thus a request from a non-readonly enabled daemon will always cause any existing delegations to be immediately revoked. Access will work but performance may be harmed since there will be a lot of revoking of delegations. Readonly enabled dameons fetching records with WANT_READONLY from non-readonly enabled daemons: Non-readonly enabled daemons ingore the WANT_READONLY flag and never return delegations. They always return a full record migration. Full record migration is allowed by the protocol, even if the originator only requests the 'hint' WANT_READONLY, so this access also interoperates between daemons with different capabilities. ctdb-2.5.1.dfsg/doc/ctdb-tunables.7.html0000644000175000017500000005156212245332464017574 0ustar mathieumathieuctdb-tunables

Name

ctdb-tunables — CTDB tunable configuration variables

DESCRIPTION

CTDB's behaviour can be configured by setting run-time tunable variables. This lists and describes all tunables. See the ctdb(1) listvars, setvar and getvar commands for more details.

MaxRedirectCount

Default: 3

If we are not the DMASTER and need to fetch a record across the network we first send the request to the LMASTER after which the record is passed onto the current DMASTER. If the DMASTER changes before the request has reached that node, the request will be passed onto the "next" DMASTER. For very hot records that migrate rapidly across the cluster this can cause a request to "chase" the record for many hops before it catches up with the record. this is how many hops we allow trying to chase the DMASTER before we switch back to the LMASTER again to ask for new directions.

When chasing a record, this is how many hops we will chase the record for before going back to the LMASTER to ask for new guidance.

SeqnumInterval

Default: 1000

Some databases have seqnum tracking enabled, so that samba will be able to detect asynchronously when there has been updates to the database. Everytime a database is updated its sequence number is increased.

This tunable is used to specify in 'ms' how frequently ctdb will send out updates to remote nodes to inform them that the sequence number is increased.

ControlTimeout

Default: 60

This is the default setting for timeout for when sending a control message to either the local or a remote ctdb daemon.

TraverseTimeout

Default: 20

This setting controls how long we allow a traverse process to run. After this timeout triggers, the main ctdb daemon will abort the traverse if it has not yet finished.

KeepaliveInterval

Default: 5

How often in seconds should the nodes send keepalives to eachother.

KeepaliveLimit

Default: 5

After how many keepalive intervals without any traffic should a node wait until marking the peer as DISCONNECTED.

If a node has hung, it can thus take KeepaliveInterval*(KeepaliveLimit+1) seconds before we determine that the node is DISCONNECTED and that we require a recovery. This limitshould not be set too high since we want a hung node to be detectec, and expunged from the cluster well before common CIFS timeouts (45-90 seconds) kick in.

RecoverTimeout

Default: 20

This is the default setting for timeouts for controls when sent from the recovery daemon. We allow longer control timeouts from the recovery daemon than from normal use since the recovery dameon often use controls that can take a lot longer than normal controls.

RecoverInterval

Default: 1

How frequently in seconds should the recovery daemon perform the consistency checks that determine if we need to perform a recovery or not.

ElectionTimeout

Default: 3

When electing a new recovery master, this is how many seconds we allow the election to take before we either deem the election finished or we fail the election and start a new one.

TakeoverTimeout

Default: 9

This is how many seconds we allow controls to take for IP failover events.

MonitorInterval

Default: 15

How often should ctdb run the event scripts to check for a nodes health.

TickleUpdateInterval

Default: 20

How often will ctdb record and store the "tickle" information used to kickstart stalled tcp connections after a recovery.

EventScriptTimeout

Default: 20

How long should ctdb let an event script run before aborting it and marking the node unhealthy.

EventScriptTimeoutCount

Default: 1

How many events in a row needs to timeout before we flag the node UNHEALTHY. This setting is useful if your scripts can not be written so that they do not hang for benign reasons.

EventScriptUnhealthyOnTimeout

Default: 0

This setting can be be used to make ctdb never become UNHEALTHY if your eventscripts keep hanging/timing out.

RecoveryGracePeriod

Default: 120

During recoveries, if a node has not caused recovery failures during the last grace period, any records of transgressions that the node has caused recovery failures will be forgiven. This resets the ban-counter back to zero for that node.

RecoveryBanPeriod

Default: 300

If a node becomes banned causing repetitive recovery failures. The node will eventually become banned from the cluster. This controls how long the culprit node will be banned from the cluster before it is allowed to try to join the cluster again. Don't set to small. A node gets banned for a reason and it is usually due to real problems with the node.

DatabaseHashSize

Default: 100001

Size of the hash chains for the local store of the tdbs that ctdb manages.

DatabaseMaxDead

Default: 5

How many dead records per hashchain in the TDB database do we allow before the freelist needs to be processed.

RerecoveryTimeout

Default: 10

Once a recovery has completed, no additional recoveries are permitted until this timeout has expired.

EnableBans

Default: 1

When set to 0, this disables BANNING completely in the cluster and thus nodes can not get banned, even it they break. Don't set to 0 unless you know what you are doing. You should set this to the same value on all nodes to avoid unexpected behaviour.

DeterministicIPs

Default: 0

When enabled, this tunable makes ctdb try to keep public IP addresses locked to specific nodes as far as possible. This makes it easier for debugging since you can know that as long as all nodes are healthy public IP X will always be hosted by node Y.

The cost of using deterministic IP address assignment is that it disables part of the logic where ctdb tries to reduce the number of public IP assignment changes in the cluster. This tunable may increase the number of IP failover/failbacks that are performed on the cluster by a small margin.

LCP2PublicIPs

Default: 1

When enabled this switches ctdb to use the LCP2 ip allocation algorithm.

ReclockPingPeriod

Default: x

Obsolete

NoIPFailback

Default: 0

When set to 1, ctdb will not perform failback of IP addresses when a node becomes healthy. Ctdb WILL perform failover of public IP addresses when a node becomes UNHEALTHY, but when the node becomes HEALTHY again, ctdb will not fail the addresses back.

Use with caution! Normally when a node becomes available to the cluster ctdb will try to reassign public IP addresses onto the new node as a way to distribute the workload evenly across the clusternode. Ctdb tries to make sure that all running nodes have approximately the same number of public addresses it hosts.

When you enable this tunable, CTDB will no longer attempt to rebalance the cluster by failing IP addresses back to the new nodes. An unbalanced cluster will therefore remain unbalanced until there is manual intervention from the administrator. When this parameter is set, you can manually fail public IP addresses over to the new node(s) using the 'ctdb moveip' command.

DisableIPFailover

Default: 0

When enabled, ctdb will not perform failover or failback. Even if a node fails while holding public IPs, ctdb will not recover the IPs or assign them to another node.

When you enable this tunable, CTDB will no longer attempt to recover the cluster by failing IP addresses over to other nodes. This leads to a service outage until the administrator has manually performed failover to replacement nodes using the 'ctdb moveip' command.

NoIPTakeover

Default: 0

When set to 1, ctdb will not allow IP addresses to be failed over onto this node. Any IP addresses that the node currently hosts will remain on the node but no new IP addresses can be failed over to the node.

NoIPHostOnAllDisabled

Default: 0

If no nodes are healthy then by default ctdb will happily host public IPs on disabled (unhealthy or administratively disabled) nodes. This can cause problems, for example if the underlying cluster filesystem is not mounted. When set to 1 on a node and that node is disabled it, any IPs hosted by this node will be released and the node will not takeover any IPs until it is no longer disabled.

DBRecordCountWarn

Default: 100000

When set to non-zero, ctdb will log a warning when we try to recover a database with more than this many records. This will produce a warning if a database grows uncontrollably with orphaned records.

DBRecordSizeWarn

Default: 10000000

When set to non-zero, ctdb will log a warning when we try to recover a database where a single record is bigger than this. This will produce a warning if a database record grows uncontrollably with orphaned sub-records.

DBSizeWarn

Default: 1000000000

When set to non-zero, ctdb will log a warning when we try to recover a database bigger than this. This will produce a warning if a database grows uncontrollably.

VerboseMemoryNames

Default: 0

This feature consumes additional memory. when used the talloc library will create more verbose names for all talloc allocated objects.

RecdPingTimeout

Default: 60

If the main dameon has not heard a "ping" from the recovery dameon for this many seconds, the main dameon will log a message that the recovery daemon is potentially hung.

RecdFailCount

Default: 10

If the recovery daemon has failed to ping the main dameon for this many consecutive intervals, the main daemon will consider the recovery daemon as hung and will try to restart it to recover.

LogLatencyMs

Default: 0

When set to non-zero, this will make the main daemon log any operation that took longer than this value, in 'ms', to complete. These include "how long time a lockwait child process needed", "how long time to write to a persistent database" but also "how long did it take to get a response to a CALL from a remote node".

RecLockLatencyMs

Default: 1000

When using a reclock file for split brain prevention, if set to non-zero this tunable will make the recovery dameon log a message if the fcntl() call to lock/testlock the recovery file takes longer than this number of ms.

RecoveryDropAllIPs

Default: 120

If we have been stuck in recovery, or stopped, or banned, mode for this many seconds we will force drop all held public addresses.

VerifyRecoveryLock

Default: 1

Should we take a fcntl() lock on the reclock file to verify that we are the sole recovery master node on the cluster or not.

VacuumInterval

Default: 10

Periodic interval in seconds when vacuuming is triggered for volatile databases.

VacuumMaxRunTime

Default: 120

The maximum time in seconds for which the vacuuming process is allowed to run. If vacuuming process takes longer than this value, then the vacuuming process is terminated.

RepackLimit

Default: 10000

During vacuuming, if the number of freelist records are more than RepackLimit, then databases are repacked to get rid of the freelist records to avoid fragmentation.

Databases are repacked only if both RepackLimit and VacuumLimit are exceeded.

VacuumLimit

Default: 5000

During vacuuming, if the number of deleted records are more than VacuumLimit, then databases are repacked to avoid fragmentation.

Databases are repacked only if both RepackLimit and VacuumLimit are exceeded.

VacuumFastPathCount

Default: 60

When a record is deleted, it is marked for deletion during vacuuming. Vacuuming process usually processes this list to purge the records from the database. If the number of records marked for deletion are more than VacuumFastPathCount, then vacuuming process will scan the complete database for empty records instead of using the list of records marked for deletion.

DeferredAttachTO

Default: 120

When databases are frozen we do not allow clients to attach to the databases. Instead of returning an error immediately to the application the attach request from the client is deferred until the database becomes available again at which stage we respond to the client.

This timeout controls how long we will defer the request from the client before timing it out and returning an error to the client.

HopcountMakeSticky

Default: 50

If the database is set to 'STICKY' mode, using the 'ctdb setdbsticky' command, any record that is seen as very hot and migrating so fast that hopcount surpasses 50 is set to become a STICKY record for StickyDuration seconds. This means that after each migration the record will be kept on the node and prevented from being migrated off the node.

This setting allows one to try to identify such records and stop them from migrating across the cluster so fast. This will improve performance for certain workloads, such as locking.tdb if many clients are opening/closing the same file concurrently.

StickyDuration

Default: 600

Once a record has been found to be fetch-lock hot and has been flagged to become STICKY, this is for how long, in seconds, the record will be flagged as a STICKY record.

StickyPindown

Default: 200

Once a STICKY record has been migrated onto a node, it will be pinned down on that node for this number of ms. Any request from other nodes to migrate the record off the node will be deferred until the pindown timer expires.

StatHistoryInterval

Default: 1

Granularity of the statistics collected in the statistics history.

AllowClientDBAttach

Default: 1

When set to 0, clients are not allowed to attach to any databases. This can be used to temporarily block any new processes from attaching to and accessing the databases.

RecoverPDBBySeqNum

Default: 1

When set to zero, database recovery for persistent databases is record-by-record and recovery process simply collects the most recent version of every individual record.

When set to non-zero, persistent databases will instead be recovered as a whole db and not by individual records. The node that contains the highest value stored in the record "__db_sequence_number__" is selected and the copy of that nodes database is used as the recovered database.

By default, recovery of persistent databses is done using __db_sequence_number__ record.

FetchCollapse

Default: 1

When many clients across many nodes try to access the same record at the same time this can lead to a fetch storm where the record becomes very active and bounces between nodes very fast. This leads to high CPU utilization of the ctdbd daemon, trying to bounce that record around very fast, and poor performance.

This parameter is used to activate a fetch-collapse. A fetch-collapse is when we track which records we have requests in flight so that we only keep one request in flight from a certain node, even if multiple smbd processes are attemtping to fetch the record at the same time. This can improve performance and reduce CPU utilization for certain workloads.

This timeout controls if we should collapse multiple fetch operations of the same record into a single request and defer all duplicates or not.

Samba3AvoidDeadlocks

Default: 0

Enable code that prevents deadlocks with Samba (only for Samba 3.x).

This should be set to 1 when using Samba version 3.x to enable special code in CTDB to avoid deadlock with Samba version 3.x. This code is not required for Samba version 4.x and must not be enabled for Samba 4.x.

SEE ALSO

ctdb(1), ctdbd(1), ctdbd.conf(5), ctdb(7), http://ctdb.samba.org/

ctdb-2.5.1.dfsg/doc/onnode.1.xml0000644000175000017500000002500112245023514016133 0ustar mathieumathieu onnode 1 ctdb CTDB - clustered TDB database onnode run commands on CTDB cluster nodes onnode OPTION NODES COMMAND DESCRIPTION onnode is a utility to run commands on a specific node of a CTDB cluster, or on all nodes. NODES specifies which node(s) to run a command on. See section NODES SPECIFICATION for details. COMMAND can be any shell command. The onnode utility uses ssh or rsh to connect to the remote nodes and run the command. OPTIONS -c Execute COMMAND in the current working directory on the specified nodes. -f FILENAME Specify an alternative nodes FILENAME to use instead of the default. This option overrides the CTDB_NODES_FILE environment variable. See the discussion of /etc/ctdb/nodes in the FILES section for more details. -i Keep standard input open, allowing data to be piped to onnode. Normally onnode closes stdin to avoid surprises when scripting. Note that this option is ignored when using or if SSH is set to anything other than "ssh". -n Allow nodes to be specified by name rather than node numbers. These nodes don't need to be listed in the nodes file. You can avoid the nodes file entirely by combining this with -f /dev/null. -o PREFIX Causes standard output from each node to be saved into a file with name PREFIX.IP. -p Run COMMAND in parallel on the specified nodes. The default is to run COMMAND sequentially on each node. -P Push files to nodes. Names of files to push are specified rather than the usual command. Quoting is fragile/broken - filenames with whitespace in them are not supported. -q Do not print node addresses. Normally, onnode prints informational node addresses if more than one node is specified. This overrides -v. -v Print node addresses even if only one node is specified. Normally, onnode prints informational node addresses when more than one node is specified. -h, --help Show a short usage guide. NODES SPECIFICATION Nodes can be specified via numeric node numbers (from 0 to N-1) or mnemonics. Multiple nodes are specified using lists of nodes, separated by commas, and ranges of numeric node numbers, separated by dashes. If nodes are specified multiple times then the command will be executed multiple times on those nodes. The order of nodes is significant. The following mnemonics are available: all All nodes. any A node where ctdbd is running. This semi-random but there is a bias towards choosing a low numbered node. ok | healthy All nodes that are not disconnected, banned, disabled or unhealthy. con | connected All nodes that are not disconnected. lvs | lvsmaster The current LVS master. natgw | natgwlist The current NAT gateway. rm | recmaster The current recovery master. EXAMPLES The following command would show the process ID of ctdbd on all nodes onnode all ctdb getpid The following command would show the last 5 lines of log on each node, preceded by the node's hostname onnode all "hostname; tail -5 /var/log/log.ctdb" The following command would restart the ctdb service on all nodes, in parallel. onnode -p all service ctdb restart The following command would run ./foo in the current working directory, in parallel, on nodes 0, 2, 3 and 4. onnode -c -p 0,2-4 ./foo ENVIRONMENT CTDB_BASE Directory containing CTDB configuration files. The default is /etc/ctdb. CTDB_NODES_FILE Name of alternative nodes file to use instead of the default. See the FILES section for more details. FILES /etc/ctdb/nodes Default file containing a list of each node's IP address or hostname. Actually, the default is $CTDB_BASE/nodes, where CTDB_BASE defaults to /etc/ctdb. If a relative path is given (via the -f option or CTDB_BASE) and no corresponding file exists relative to the current directory then the file is also searched for in the $CTDB_BASE directory. /etc/ctdb/onnode.conf If this file exists it is sourced by onnode. The main purpose is to allow the administrator to set SSH to something other than "ssh". In this case the -t option is ignored. For example, the administrator may choose to use use rsh instead of ssh. SEE ALSO ctdb 7, This documentation was written by Andrew Tridgell, Martin Schwenke 2007 Andrew Tridgell Ronnie Sahlberg 2008 Martin Schwenke This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb-2.5.1.dfsg/doc/ping_pong.10000644000175000017500000000626412245332462016051 0ustar mathieumathieu'\" t .\" Title: ping_pong .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "PING_PONG" "1" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ping_pong \- measures the ping\-pong byte range lock latency .SH "SYNOPSIS" .HP \w'\fBping_pong\fR\ 'u \fBping_pong\fR {\-r | \-w | \-rw} [\-m] [\-c] {\fIFILENAME\fR} {\fINUM\-LOCKS\fR} .SH "DESCRIPTION" .PP ping_pong measures the byte range lock latency\&. It is especially useful on a cluster of nodes sharing a common lock manager as it will give some indication of the lock manager\*(Aqs performance under stress\&. .PP FILENAME is a file on shared storage to use for byte range locking tests\&. .PP NUM\-LOCKS is the number of byte range locks, so needs to be (strictly) greater than the number of nodes in the cluster\&. .SH "OPTIONS" .PP \-r .RS 4 test read performance .RE .PP \-w .RS 4 test write performance .RE .PP \-m .RS 4 use mmap .RE .PP \-c .RS 4 validate the locks .RE .SH "EXAMPLES" .PP Testing lock coherence .sp .if n \{\ .RS 4 .\} .nf ping_pong test\&.dat N .fi .if n \{\ .RE .\} .PP Testing lock coherence with lock validation .sp .if n \{\ .RS 4 .\} .nf ping_pong \-c test\&.dat N .fi .if n \{\ .RE .\} .PP Testing IO coherence .sp .if n \{\ .RS 4 .\} .nf ping_pong \-rw test\&.dat N .fi .if n \{\ .RE .\} .SH "SEE ALSO" .PP \fBctdb\fR(7), \m[blue]\fB\%https://wiki.samba.org/index.php/Ping_pong\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Mathieu Parent .SH "COPYRIGHT" .br Copyright \(co 2002 Andrew Tridgell .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp ctdb-2.5.1.dfsg/doc/ctdb.7.html0000644000175000017500000006717212245332463015764 0ustar mathieumathieuctdb

Name

ctdb — Clustered TDB

DESCRIPTION

CTDB is a clustered database component in clustered Samba that provides a high-availability load-sharing CIFS server cluster.

The main functions of CTDB are:

  • Provide a clustered version of the TDB database with automatic rebuild/recovery of the databases upon node failures.

  • Monitor nodes in the cluster and services running on each node.

  • Manage a pool of public IP addresses that are used to provide services to clients. Alternatively, CTDB can be used with LVS.

Combined with a cluster filesystem CTDB provides a full high-availablity (HA) environment for services such as clustered Samba, NFS and other services.

ANATOMY OF A CTDB CLUSTER

A CTDB cluster is a collection of nodes with 2 or more network interfaces. All nodes provide network (usually file/NAS) services to clients. Data served by file services is stored on shared storage (usually a cluster filesystem) that is accessible by all nodes.

CTDB provides an "all active" cluster, where services are load balanced across all nodes.

Private vs Public addresses

Each node in a CTDB cluster has multiple IP addresses assigned to it:

  • A single private IP address that is used for communication between nodes.

  • One or more public IP addresses that are used to provide NAS or other services.

Private address

Each node is configured with a unique, permanently assigned private address. This address is configured by the operating system. This address uniquely identifies a physical node in the cluster and is the address that CTDB daemons will use to communicate with the CTDB daemons on other nodes.

Private addresses are listed in the file specified by the CTDB_NODES configuration variable (see ctdbd.conf(5), default /etc/ctdb/nodes). This file contains the list of private addresses for all nodes in the cluster, one per line. This file must be the same on all nodes in the cluster.

Private addresses should not be used by clients to connect to services provided by the cluster.

It is strongly recommended that the private addresses are configured on a private network that is separate from client networks.

Example /etc/ctdb/nodes for a four node cluster:

192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
      

Public addresses

Public addresses are used to provide services to clients. Public addresses are not configured at the operating system level and are not permanently associated with a particular node. Instead, they are managed by CTDB and are assigned to interfaces on physical nodes at runtime.

The CTDB cluster will assign/reassign these public addresses across the available healthy nodes in the cluster. When one node fails, its public addresses will be taken over by one or more other nodes in the cluster. This ensures that services provided by all public addresses are always available to clients, as long as there are nodes available capable of hosting this address.

The public address configuration is stored in a file on each node specified by the CTDB_PUBLIC_ADDRESSES configuration variable (see ctdbd.conf(5), recommended /etc/ctdb/public_addresses). This file contains a list of the public addresses that the node is capable of hosting, one per line. Each entry also contains the netmask and the interface to which the address should be assigned.

Example /etc/ctdb/public_addresses for a node that can host 4 public addresses, on 2 different interfaces:

10.1.1.1/24 eth1
10.1.1.2/24 eth1
10.1.2.1/24 eth2
10.1.2.2/24 eth2
      

In many cases the public addresses file will be the same on all nodes. However, it is possible to use different public address configurations on different nodes.

Example: 4 nodes partitioned into two subgroups:

Node 0:/etc/ctdb/public_addresses
	10.1.1.1/24 eth1
	10.1.1.2/24 eth1

Node 1:/etc/ctdb/public_addresses
	10.1.1.1/24 eth1
	10.1.1.2/24 eth1

Node 2:/etc/ctdb/public_addresses
	10.1.2.1/24 eth2
	10.1.2.2/24 eth2

Node 3:/etc/ctdb/public_addresses
	10.1.2.1/24 eth2
	10.1.2.2/24 eth2
      

In this example nodes 0 and 1 host two public addresses on the 10.1.1.x network while nodes 2 and 3 host two public addresses for the 10.1.2.x network.

Public address 10.1.1.1 can be hosted by either of nodes 0 or 1 and will be available to clients as long as at least one of these two nodes are available.

If both nodes 0 and 1 become unavailable then public address 10.1.1.1 also becomes unavailable. 10.1.1.1 can not be failed over to nodes 2 or 3 since these nodes do not have this public address configured.

The ctdb ip command can be used to view the current assignment of public addresses to physical nodes.

Node status

The current status of each node in the cluster can be viewed by the ctdb status command.

A node can be in one of the following states:

OK

This node is healthy and fully functional. It hosts public addresses to provide services.

DISCONNECTED

This node is not reachable by other nodes via the private network. It is not currently participating in the cluster. It does not host public addresses to provide services. It might be shut down.

DISABLED

This node has been administratively disabled. This node is partially functional and participates in the cluster. However, it does not host public addresses to provide services.

UNHEALTHY

A service provided by this node has failed a health check and should be investigated. This node is partially functional and participates in the cluster. However, it does not host public addresses to provide services. Unhealthy nodes should be investigated and may require an administrative action to rectify.

BANNED

CTDB is not behaving as designed on this node. For example, it may have failed too many recovery attempts. Such nodes are banned from participating in the cluster for a configurable time period before they attempt to rejoin the cluster. A banned node does not host public addresses to provide services. All banned nodes should be investigated and may require an administrative action to rectify.

STOPPED

This node has been administratively exclude from the cluster. A stopped node does no participate in the cluster and does not host public addresses to provide services. This state can be used while performing maintenance on a node.

PARTIALLYONLINE

A node that is partially online participates in a cluster like a healthy (OK) node. Some interfaces to serve public addresses are down, but at least one interface is up. See also ctdb ifaces.

CAPABILITIES

Cluster nodes can have several different capabilities enabled. These are listed below.

RECMASTER

Indicates that a node can become the CTDB cluster recovery master. The current recovery master is decided via an election held by all active nodes with this capability.

Default is YES.

LMASTER

Indicates that a node can be the location master (LMASTER) for database records. The LMASTER always knows which node has the latest copy of a record in a volatile database.

Default is YES.

LVS

Indicates that a node is configued in Linux Virtual Server (LVS) mode. In this mode the entire CTDB cluster uses one single public address for the entire cluster instead of using multiple public addresses in failover mode. This is an alternative to using a load-balancing layer-4 switch. See the LVS section for more details.

NATGW

Indicates that this node is configured to become the NAT gateway master in a NAT gateway group. See the NAT GATEWAY section for more details.

The RECMASTER and LMASTER capabilities can be disabled when CTDB is used to create a cluster spanning across WAN links. In this case CTDB acts as a WAN accelerator.

LVS

LVS is a mode where CTDB presents one single IP address for the entire cluster. This is an alternative to using public IP addresses and round-robin DNS to loadbalance clients across the cluster.

This is similar to using a layer-4 loadbalancing switch but with some restrictions.

In this mode the cluster selects a set of nodes in the cluster and loadbalance all client access to the LVS address across this set of nodes. This set of nodes are all LVS capable nodes that are HEALTHY, or if no HEALTHY nodes exists all LVS capable nodes regardless of health status. LVS will however never loadbalance traffic to nodes that are BANNED, STOPPED, DISABLED or DISCONNECTED. The ctdb lvs command is used to show which nodes are currently load-balanced across.

One of the these nodes are elected as the LVSMASTER. This node receives all traffic from clients coming in to the LVS address and multiplexes it across the internal network to one of the nodes that LVS is using. When responding to the client, that node will send the data back directly to the client, bypassing the LVSMASTER node. The command ctdb lvsmaster will show which node is the current LVSMASTER.

The path used for a client I/O is:

  1. Client sends request packet to LVSMASTER.

  2. LVSMASTER passes the request on to one node across the internal network.

  3. Selected node processes the request.

  4. Node responds back to client.

This means that all incoming traffic to the cluster will pass through one physical node, which limits scalability. You can send more data to the LVS address that one physical node can multiplex. This means that you should not use LVS if your I/O pattern is write-intensive since you will be limited in the available network bandwidth that node can handle. LVS does work wery well for read-intensive workloads where only smallish READ requests are going through the LVSMASTER bottleneck and the majority of the traffic volume (the data in the read replies) goes straight from the processing node back to the clients. For read-intensive i/o patterns you can acheive very high throughput rates in this mode.

Note: you can use LVS and public addresses at the same time.

If you use LVS, you must have a permanent address configured for the public interface on each node. This address must be routable and the cluster nodes must be configured so that all traffic back to client hosts are routed through this interface. This is also required in order to allow samba/winbind on the node to talk to the domain controller. This LVS IP address can not be used to initiate outgoing traffic.

Make sure that the domain controller and the clients are reachable from a node before you enable LVS. Also ensure that outgoing traffic to these hosts is routed out through the configured public interface.

Configuration

To activate LVS on a CTDB node you must specify the CTDB_PUBLIC_INTERFACE and CTDB_LVS_PUBLIC_IP configuration variables. Setting the latter variable also enables the LVS capability on the node at startup.

Example:

CTDB_PUBLIC_INTERFACE=eth1
CTDB_LVS_PUBLIC_IP=10.1.1.237
	

NAT GATEWAY

NAT gateway (NATGW) is an optional feature that is used to configure fallback routing for nodes. This allows cluster nodes to connect to external services (e.g. DNS, AD, NIS and LDAP) when they do not host any public addresses (e.g. when they are unhealthy).

This also applies to node startup because CTDB marks nodes as UNHEALTHY until they have passed a "monitor" event. In this context, NAT gateway helps to avoid a "chicken and egg" situation where a node needs to access an external service to become healthy.

Another way of solving this type of problem is to assign an extra static IP address to a public interface on every node. This is simpler but it uses an extra IP address per node, while NAT gateway generally uses only one extra IP address.

Operation

One extra NATGW public address is assigned on the public network to each NATGW group. Each NATGW group is a set of nodes in the cluster that shares the same NATGW address to talk to the outside world. Normally there would only be one NATGW group spanning an entire cluster, but in situations where one CTDB cluster spans multiple physical sites it might be useful to have one NATGW group for each site.

There can be multiple NATGW groups in a cluster but each node can only be member of one NATGW group.

In each NATGW group, one of the nodes is selected by CTDB to be the NATGW master and the other nodes are consider to be NATGW slaves. NATGW slaves establish a fallback default route to the NATGW master via the private network. When a NATGW slave hosts no public IP addresses then it will use this route for outbound connections. The NATGW master hosts the NATGW public IP address and routes outgoing connections from slave nodes via this IP address. It also establishes a fallback default route.

Configuration

NATGW is usually configured similar to the following example configuration:

CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24
CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
CTDB_NATGW_PUBLIC_IFACE=eth0
CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
      

Normally any node in a NATGW group can act as the NATGW master. Some configurations may have special nodes that lack connectivity to a public network. In such cases, CTDB_NATGW_SLAVE_ONLY can be used to limit the NATGW functionality of thos nodes.

See the NAT GATEWAY section in ctdb.conf(5) for more details of NATGW configuration.

Implementation details

When the NATGW functionality is used, one of the nodes is selected to act as a NAT gateway for all the other nodes in the group when they need to communicate with the external services. The NATGW master is selected to be a node that is most likely to have usable networks.

The NATGW master hosts the NATGW public IP address CTDB_NATGW_PUBLIC_IP on the configured public interfaces CTDB_NATGW_PUBLIC_IFACE and acts as a router, masquerading outgoing connections from slave nodes via this IP address. It also establishes a fallback default route to the configured default gateway CTDB_NATGW_DEFAULT_GATEWAY with a metric of 10. A metric 10 route is used so it can co-exist with other default routes that may be available.

A NATGW slave establishes its fallback default route to the NATGW master via the private network CTDB_NATGW_PRIVATE_NETWORKwith a metric of 10. This route is used for outbound connections when no other default route is available because the node hosts no public addresses. A metric 10 routes is used so that it can co-exist with other default routes that may be available when the node is hosting public addresses.

This is implemented in the 11.natgw eventscript. Please see the eventscript file for the finer details.

POLICY ROUTING

Policy routing is an optional CTDB feature to support complex network topologies. Public addresses may be spread across several different networks (or VLANs) and it may not be possible to route packets from these public addresses via the system's default route. Therefore, CTDB has support for policy routing via the 13.per_ip_routing eventscript. This allows routing to be specified for packets sourced from each public address. The routes are added and removed as CTDB moves public addresses between nodes.

Configuration variables

There are 4 configuration variables related to policy routing: CTDB_PER_IP_ROUTING_CONF, CTDB_PER_IP_ROUTING_RULE_PREF, CTDB_PER_IP_ROUTING_TABLE_ID_LOW, CTDB_PER_IP_ROUTING_TABLE_ID_HIGH. See the POLICY ROUTING section in ctdbd.conf(5) for more details.

Configuration

The format of each line of CTDB_PER_IP_ROUTING_CONF is:

<public_address> <network> [ <gateway> ]
      

Leading whitespace is ignored and arbitrary whitespace may be used as a separator. Lines that have a "public address" item that doesn't match an actual public address are ignored. This means that comment lines can be added using a leading character such as '#', since this will never match an IP address.

A line without a gateway indicates a link local route.

For example, consider the configuration line:

  192.168.1.99	192.168.1.1/24
      

If the corresponding public_addresses line is:

  192.168.1.99/24     eth2,eth3
      

CTDB_PER_IP_ROUTING_RULE_PREF is 100, and CTDB adds the address to eth2 then the following routing information is added:

  ip rule add from 192.168.1.99 pref 100 table ctdb.192.168.1.99
  ip route add 192.168.1.0/24 dev eth2 table ctdb.192.168.1.99
      

This causes traffic from 192.168.1.1 to 192.168.1.0/24 go via eth2.

The ip rule command will show (something like - depending on other public addresses and other routes on the system):

  0:		from all lookup local 
  100:		from 192.168.1.99 lookup ctdb.192.168.1.99
  32766:	from all lookup main 
  32767:	from all lookup default 
      

ip route show table ctdb.192.168.1.99 will show:

  192.168.1.0/24 dev eth2 scope link
      

The usual use for a line containing a gateway is to add a default route corresponding to a particular source address. Consider this line of configuration:

  192.168.1.99	0.0.0.0/0	192.168.1.1
      

In the situation described above this will cause an extra routing command to be executed:

  ip route add 0.0.0.0/0 via 192.168.1.1 dev eth2 table ctdb.192.168.1.99
      

With both configuration lines, ip route show table ctdb.192.168.1.99 will show:

  192.168.1.0/24 dev eth2 scope link 
  default via 192.168.1.1 dev eth2 
      

Sample configuration

Here is a more complete example configuration.

/etc/ctdb/public_addresses:

  192.168.1.98	eth2,eth3
  192.168.1.99	eth2,eth3

/etc/ctdb/policy_routing:

  192.168.1.98 192.168.1.0/24
  192.168.1.98 192.168.200.0/24	192.168.1.254
  192.168.1.98 0.0.0.0/0 	192.168.1.1
  192.168.1.99 192.168.1.0/24
  192.168.1.99 192.168.200.0/24	192.168.1.254
  192.168.1.99 0.0.0.0/0 	192.168.1.1
      

The routes local packets as expected, the default route is as previously discussed, but packets to 192.168.200.0/24 are routed via the alternate gateway 192.168.1.254.

NOTIFICATION SCRIPT

When certain state changes occur in CTDB, it can be configured to perform arbitrary actions via a notification script. For example, sending SNMP traps or emails when a node becomes unhealthy or similar.

This is activated by setting the CTDB_NOTIFY_SCRIPT configuration variable. The specified script must be executable.

Use of the provided /etc/ctdb/notify.sh script is recommended. It executes files in /etc/ctdb/notify.d/.

CTDB currently generates notifications after CTDB changes to these states:

init
setup
startup
healthy
unhealthy

DEBUG LEVELS

Valid values for DEBUGLEVEL are:

EMERG (-3)
ALERT (-2)
CRIT (-1)
ERR (0)
WARNING (1)
NOTICE (2)
INFO (3)
DEBUG (4)

REMOTE CLUSTER NODES

It is possible to have a CTDB cluster that spans across a WAN link. For example where you have a CTDB cluster in your datacentre but you also want to have one additional CTDB node located at a remote branch site. This is similar to how a WAN accelerator works but with the difference that while a WAN-accelerator often acts as a Proxy or a MitM, in the ctdb remote cluster node configuration the Samba instance at the remote site IS the genuine server, not a proxy and not a MitM, and thus provides 100% correct CIFS semantics to clients.

See the cluster as one single multihomed samba server where one of the NICs (the remote node) is very far away.

NOTE: This does require that the cluster filesystem you use can cope with WAN-link latencies. Not all cluster filesystems can handle WAN-link latencies! Whether this will provide very good WAN-accelerator performance or it will perform very poorly depends entirely on how optimized your cluster filesystem is in handling high latency for data and metadata operations.

To activate a node as being a remote cluster node you need to set the following two parameters in /etc/sysconfig/ctdb for the remote node:

CTDB_CAPABILITY_LMASTER=no
CTDB_CAPABILITY_RECMASTER=no
	

Verify with the command "ctdb getcapabilities" that that node no longer has the recmaster or the lmaster capabilities.

SEE ALSO

ctdb(1), ctdbd(1), ctdbd_wrapper(1), ltdbtool(1), onnode(1), ping_pong(1), ctdbd.conf(5), ctdb-tunables(7), http://ctdb.samba.org/

ctdb-2.5.1.dfsg/doc/Makefile0000644000175000017500000000100612245023514015427 0ustar mathieumathieuDOCS = ctdb.1 ctdb.1.html \ ctdbd.1 ctdbd.1.html \ ctdbd_wrapper.1 ctdbd_wrapper.1.html \ onnode.1 onnode.1.html \ ltdbtool.1 ltdbtool.1.html \ ping_pong.1 ping_pong.1.html \ ctdbd.conf.5 ctdbd.conf.5.html \ ctdb.7 ctdb.7.html \ ctdb-tunables.7 ctdb-tunables.7.html all: $(DOCS) %: %.xml xsltproc -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< %.html: %.xml xsltproc -o $@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl $< distclean: rm -f $(DOCS) ctdb-2.5.1.dfsg/doc/ctdbd_wrapper.10000644000175000017500000000511712245332460016703 0ustar mathieumathieu'\" t .\" Title: ctdbd_wrapper .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "CTDBD_WRAPPER" "1" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ctdbd_wrapper \- Wrapper for ctdbd .SH "SYNOPSIS" .HP \w'\fBctdbd_wrapper\fR\ 'u \fBctdbd_wrapper\fR {\fIPIDFILE\fR} {start | stop} .SH "DESCRIPTION" .PP ctdbd_wrapper is used to start or stop the main CTDB daemon\&. .PP \fIPIDFILE\fR specifies the location of the file containing the PID of the main CTDB daemon\&. .PP ctdbd_wrapper constructs command\-line options for ctdbd from configuration variables specified in \fBctdbd.conf\fR(5)\&. .PP See \fBctdb\fR(7) for an overview of CTDB\&. .SH "SEE ALSO" .PP \fBctdbd\fR(1), \fBctdbd.conf\fR(5), \fBctdb\fR(7), \m[blue]\fB\%http://ctdb.samba.org/\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Amitay Isaacs, Martin Schwenke .SH "COPYRIGHT" .br Copyright \(co 2007 Andrew Tridgell, Ronnie Sahlberg .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp ctdb-2.5.1.dfsg/doc/ctdbd.conf.5.xml0000644000175000017500000012006012245023514016662 0ustar mathieumathieu ctdbd.conf 5 ctdb CTDB - clustered TDB database ctdbd.conf CTDB daemon configuration file DESCRIPTION This file contains CTDB configuration variables that are affect the operation of CTDB. The default location of this file is /etc/ctdb/ctdbd.conf. This file is a shell script (see sh 1) but is usually limited to simple variable assignments and shell-style comments. CTDB configuration variables are grouped into several categories below. Variables defined in this document can also be set in a distribution-specific configuration file such as /etc/sysconfig/ctdb (Red Hat) or /etc/default/ctdb (Debian). However, these files should be reserved for variables used by the initscript. A historical alternative is /etc/ctdb/sysconfig/ctdb - this is deprecated. INITSCRIPT CONFIGURATION Some options must be available to the initscript so they need to be set in the distribution-specific initscript configuration, such as /etc/sysconfig/ctdb or /etc/default/ctdb. CTDB_PIDFILE=FILENAME FILENAME is the name of the file used to contain the process ID (PID) of the main CTDB daemon when it is running. This is passed from the initscript to ctdbd_wrapper 1. Default is /var/run/ctdb/ctdbd.pid. Corresponds to . GLOBAL CONFIGURATION These options may be used in the initscripts, daemon and scripts. CTDB_BASE=DIRECTORY DIRECTORY containing CTDB scripts and configuration files. CTDB_VARDIR=DIRECTORY DIRECTORY containing CTDB files that are modified at runtime. Defaults to /var/ctdb, unless /var/lib/ctdb already exists in which case it is used. DAEMON CONFIGURATION Variables in this section are processed by ctdbd_wrapper 1 and are converted into command-line arguments to ctdbd 1. Correspondence with ctdbd 1 options is shown for each variable. The the documentation for the relevant options for more details. Many of these variables are also used by event scripts. CTDB_CAPABILITY_LMASTER=yes|no Defaults to yes. Corresponds to . CTDB_CAPABILITY_RECMASTER=yes|no Defaults to yes. Corresponds to . CTDB_DBDIR=DIRECTORY Defaults to CTDB_VARDIR. Corresponds to . CTDB_DBDIR_PERSISTENT=DIRECTORY Defaults to CTDB_VARDIR/persistent. Corresponds to . CTDB_DBDIR_STATE=DIRECTORY Defaults to CTDB_VARDIR/state. Corresponds to . CTDB_DEBUGLEVEL=DEBUGLEVEL Default is ERR (0). Corresponds to or . CTDB_EVENT_SCRIPT_DIR=DIRECTORY Default is CTDB_BASE/events.d, so usually /etc/ctdb/events.d. Corresponds to . CTDB_LOGFILE=FILENAME Defaults to /var/log/log.ctdb. Corresponds to . See also CTDB_SYSLOG. CTDB_LOG_RINGBUF_SIZE=NUM Default is 0. Corresponds to . CTDB_LVS_PUBLIC_IP=IPADDR No default. Corresponds to " . CTDB_NODES=FILENAME Default is CTDB_BASE/nodes, so usually /etc/ctdb/nodes. Corresponds to . CTDB_NOTIFY_SCRIPT=FILENAME No default, usually /etc/ctdb/notify.sh. Corresponds to . CTDB_MAX_PERSISTENT_CHECK_ERRORS=NUM Default 0. Corresponds to . CTDB_PUBLIC_ADDRESSES=FILENAME No default, usually /etc/ctdb/public_addresses. Corresponds to . CTDB_PUBLIC_INTERFACE=INTERFACE No default. Corresponds to . CTDB_RECOVERY_LOCK=FILENAME Defaults to /some/place/on/shared/storage, which should be change to a useful value. Corresponds to . CTDB_SCRIPT_LOG_LEVEL=DEBUGLEVEL Defaults to ERR (0). Corresponds to . CTDB_SOCKET=FILENAME Defaults to /tmp/ctdb.socket. Corresponds to . If you change this then you probably want to set this in root's enviroment (perhaps in a file in /etc/profile.d) so that you can use the ctdb 1 command in a straightforward manner. CTDB_START_AS_DISABLED=yes|no Default is no. Corresponds to . CTDB_START_AS_STOPPED=yes|no Default is no. Corresponds to . CTDB_SYSLOG=yes|no Default is no. Corresponds to . CTDB_TRANSPORT=tcp|infiniband Defaults to tcp. Corresponds to . While the following variables do not translate into daemon options they are used by ctdbd_wrapper 1 when starting and stopping ctdbd 1. CTDB_SHUTDOWN_TIMEOUT=NUM NUM is the number of seconds to wait for ctdbd 1 to shut down gracefully before giving up and killing it. Defaults is 30. CTDB_STARTUP_TIMEOUT=NUM NUM is the number of seconds to wait for ctdbd 1 complete early initialisation up to a point where it is unlikely to abort. If ctdbd doesn't complete the "setup" event before this timeout then it is killed. Defaults is 10. NETWORK CONFIGURATION NAT GATEWAY NAT gateway is used to configure fallback routing for nodes when they do not host any public IP addresses. For example, it allows unhealthy nodes to reliably communicate with external infrastructure. One node in a NAT gateway group will be designated as the NAT gateway master node and other (slave) nodes will be configured with fallback routes via the NAT gateway master node. For more information, see the NAT GATEWAY section in ctdb 7. CTDB_NATGW_DEFAULT_GATEWAY=IPADDR IPADDR is an alternate network gateway to use on the NAT gateway master node. A fallback default route is added via this network gateway. No default. CTDB_NATGW_NODES=FILENAME FILENAME contains the list of nodes that belong to the same NAT gateway group. File format: IPADDR No default, usually /etc/ctdb/natgw_nodes when enabled. CTDB_NATGW_PRIVATE_NETWORK=IPADDR/MASK IPADDR/MASK is the private sub-network that is internally routed via the NAT gateway master node. This is usually the private network that is used for node addresses. No default. CTDB_NATGW_PUBLIC_IFACE=IFACE IFACE is the network interface on which the CTDB_NATGW_PUBLIC_IP will be configured. No default. CTDB_NATGW_PUBLIC_IP=IPADDR/MASK IPADDR/MASK indicates the IP address that is used for outgoing traffic (originating from CTDB_NATGW_PRIVATE_NETWORK) on the NAT gateway master node. This must not be a configured public IP address. No default. CTDB_NATGW_SLAVE_ONLY=yes|no When set to "yes" a node can not be a NAT gateway master node. Default is no. Example CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24 CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1 CTDB_NATGW_PUBLIC_IP=10.0.0.227/24 CTDB_NATGW_PUBLIC_IFACE=eth0 POLICY ROUTING A node running CTDB may be a component of a complex network topology. In particular, public addresses may be spread across several different networks (or VLANs) and it may not be possible to route packets from these public addresses via the system's default route. Therefore, CTDB has support for policy routing via the 13.per_ip_routing eventscript. This allows routing to be specified for packets sourced from each public address. The routes are added and removed as CTDB moves public addresses between nodes. For more information, see the POLICY ROUTING section in ctdb 7. CTDB_PER_IP_ROUTING_CONF=FILENAME FILENAME contains elements for constructing the desired routes for each source address. The special FILENAME value __auto_link_local__ indicates that no configuration file is provided and that CTDB should generate reasonable link-local routes for each public IP address. File format: IPADDR DEST-IPADDR/MASK GATEWAY-IPADDR No default, usually /etc/ctdb/policy_routing when enabled. CTDB_PER_IP_ROUTING_RULE_PREF=NUM NUM sets the priority (or preference) for the routing rules that are added by CTDB. This should be (strictly) greater than 0 and (strictly) less than 32766. A priority of 100 is recommended, unless this conflicts with a priority already in use on the system. See ip 8, for more details. CTDB_PER_IP_ROUTING_TABLE_ID_LOW=LOW-NUM, CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=HIGH-NUM CTDB determines a unique routing table number to use for the routing related to each public address. LOW-NUM and HIGH-NUM indicate the minimum and maximum routing table numbers that are used. ip 8 uses some reserved routing table numbers below 255. Therefore, CTDB_PER_IP_ROUTING_TABLE_ID_LOW should be (strictly) greater than 255. CTDB uses the standard file /etc/iproute2/rt_tables to maintain a mapping between the routing table numbers and labels. The label for a public address ADDR will look like ctdb.addr. This means that the associated rules and routes are easy to read (and manipulate). No default, usually 1000 and 9000. Example CTDB_PER_IP_ROUTING_CONF=/etc/ctdb/policy_routing CTDB_PER_IP_ROUTING_RULE_PREF=100 CTDB_PER_IP_ROUTING_TABLE_ID_LOW=1000 CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000 MISCELLANEOUS NETWORK CONFIGURATION CTDB_PARTIALLY_ONLINE_INTERFACES=yes|no Whether one or more offline interfaces should cause a monitor event to fail if there are other interfaces that are up. If this is "yes" and a node has some interfaces that are down then ctdb status will display the node as "PARTIALLYONLINE". Default is "no". SERVICE CONFIGURATION CTDB can be configured to manage and/or monitor various NAS (and other) services via its eventscripts. In the simplest case CTDB will manage a service. This means the service will be started and stopped along with CTDB, CTDB will monitor the service and CTDB will do any required reconfiguration of the service when public IP addresses are failed over. SAMBA Eventscripts 49.winbind 50.samba CTDB_MANAGES_SAMBA=yes|no Should CTDB manage Samba? Default is no. CTDB_MANAGES_WINBIND=yes|no Should CTDB manage Winbind? Default is no. CTDB_SAMBA_CHECK_PORTS=PORT-LIST When monitoring Samba, check TCP ports in space-separated PORT-LIST. Default is to monitor ports that Samba is configured to listen on. CTDB_SAMBA_SKIP_SHARE_CHECK=yes|no As part of monitoring, should CTDB skip the check for the existence of each directory configured as share in Samba. This may be desirable if there is a large number of shares. Default is no. CTDB_SERVICE_NMB=SERVICE Distribution specific SERVICE for managing nmbd. Default is distribution-dependant. CTDB_SERVICE_SMB=SERVICE Distribution specific SERVICE for managing smbd. Default is distribution-dependant. CTDB_SERVICE_WINBIND=SERVICE Distribution specific SERVICE for managing winbindd. Default is "winbind". NFS This includes parameters for the kernel NFS server and the user-space NFS-Ganesha server. Eventscripts 60.nfs 60.ganesha CTDB_CLUSTER_FILESYSTEM_TYPE=gpfs The type of cluster filesystem to use with NFS-ganesha. Currently only "gpfs" is supported. Default is "gpfs". CTDB_MANAGES_NFS=yes|no Should CTDB manage NFS? Default is no. CTDB_MONITOR_NFS_THREAD_COUNT=yes|no Whether to monitor the NFS kernel server thread count. This works around a limitation in some NFS initscripts where some threads can be stuck in host filesystem calls (perhaps due to slow storage), a restart occurs, some threads don't exit, the start only adds the missing number of threads, the stuck threads exit, and the result is a lower than expected thread count. Note that if you must also set RPCNFSDCOUNT (RedHat/Debian) or USE_KERNEL_NFSD_NUMBER (SUSE) in your NFS configuration so the monitoring code knows how many threads there should be - if neither of these are set then this option will be ignored. Default is no. CTDB_NFS_DUMP_STUCK_THREADS=NUM NUM is the number of NFS kernel server threads to dump stack traces for if some are still alive after stopping NFS during a restart. Default is 0. CTDB_NFS_SERVER_MODE=kernel|ganesha Selects which NFS server to be managed. This replaces the deprecated variable NFS_SERVER_MODE. Default is "kernel". CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK=yes|no During monitoring, should CTDB skip the rpcinfo check that is used to see if the NFS kernel server is functional. Default is no. CTDB_NFS_SKIP_SHARE_CHECK=yes|no As part of monitoring, should CTDB skip the check for the existence of each directory exported via NFS. This may be desirable if there is a large number of exports. Default is no. CTDB_RPCINFO_LOCALHOST=IPADDR|HOSTNAME IPADDR or HOSTNAME indicates the address that rpcinfo should connect to when doing rpcinfo check on RPC service during monitoring. Optimally this would be "localhost". However, this can add some performance overheads. Default is "127.0.0.1". CTDB_SKIP_GANESHA_NFSD_CHECK=yes|no As part of monitoring, should CTDB skip the check for the existence of each directory exported via NFS-Ganesha. This may be desirable if there is a large number of exports. Default is no. APACHE HTTPD CTDB can manage the Apache web server. Eventscript 41.httpd CTDB_MANAGES_HTTPD=yes|no Should CTDB manage the Apache web server? Default is no. CLAMAV CTDB has support to manage the popular anti-virus daemon ClamAV. Eventscript 31.clamd This eventscript is not enabled by default. Use ctdb enablescript to enable it. CTDB_MANAGES_CLAMD=yes|no Should CTDB manage ClamAV? Default is no. CTDB_CLAMD_SOCKET=FILENAME FILENAME is the socket to monitor ClamAV. No default. ISCSI CTDB has support for managing the Linux iSCSI tgtd service. Eventscript 70.iscsi CTDB_MANAGES_ISCSI=yes|no Should CTDB manage iSCSI tgtd? Default is no. CTDB_START_ISCSI_SCRIPTS=DIRECTORY DIRECTORY on shared storage containing scripts to start tgtd for each public IP address. No default. MULTIPATHD CTDB can monitor multipath devices to ensure that active paths are available. Eventscript 20.multipathd This eventscript is not enabled by default. Use ctdb enablescript to enable it. CTDB_MONITOR_MPDEVICES=MP-DEVICE-LIST MP-DEVICE-LIST is a list of multipath devices for CTDB to monitor? No default. VSFTPD CTDB can manage the vsftpd FTP server. Eventscript 40.vsftpd CTDB_MANAGES_VSFTPD=yes|no Should CTDB manage the vsftpd FTP server? Default is no. SYSTEM RESOURCE MONITORING CONFIGURATION CTDB can experience seemingly random (performance and other) issues if system resources become too contrained. Options in this section can be enabled to allow certain system resources to be checked. Eventscripts 00.ctdb 40.fs_use Filesystem usage monitoring is in 40.fs_use. This eventscript is not enabled by default. Use ctdb enablescript to enable it. CTDB_CHECK_FS_USE=FS-LIMIT-LIST FS-LIMIT-LIST is a space-separated list of FILESYSTEM:LIMIT pairs indicating that a node should be flagged unhealthy if the space used on FILESYSTEM reaches LIMIT%. No default. Note that this feature uses the 40.fs_use eventscript, which is not enabled by default. Use ctdb enablescript to enable it. CTDB_CHECK_SWAP_IS_NOT_USED=yes|no Should a warning be logged if swap space is in use. Default is no. CTDB_MONITOR_FREE_MEMORY=NUM NUM is a lower limit on available system memory, expressed in megabytes. If this is set and the amount of available memory falls below this limit then some debug information will be logged, the node will be disabled and then CTDB will be shut down. No default. CTDB_MONITOR_FREE_MEMORY_WARN=NUM NUM is a lower limit on available system memory, expressed in megabytes. If this is set and the amount of available memory falls below this limit then a warning will be logged. No default. MISCELLANEOUS SERVICE-RELATED CONFIGURATION CTDB_MANAGED_SERVICES=SERVICE-LIST SERVICE-LIST is a space-separated list of SERVICEs that CTDB should manage. This can be used as an alternative to the CTDB_MANAGES_SERVICE variables. No default. CTDB_SERVICE_AUTOSTARTSTOP=yes|no When CTDB should start and stop services if they become managed or unmanaged. Default is no. TUNABLES CONFIGURATION CTDB tunables (see ctdbd-tunables 7) can be set from the configuration file. They are set as follows: CTDB_SET_TUNABLE=VALUE For example: CTDB_SET_MonitorInterval=20 DEBUG AND TEST Variable in this section are for debugging and testing CTDB. They should not generally be needed. CTDB_DEBUG_HUNG_SCRIPT=FILENAME FILENAME is a script to run to log debug information when an event script times out. Default is CTDB_BASE/debug-hung-script.sh. CTDB_DEBUG_LOCKS=FILENAME FILENAME is a script to run to log debug information when an CTDB fails to freeze databases during recovery. No default, usually CTDB_BASE/debug_locks.sh. CTDB_ETCDIR=DIRECTORY DIRECTORY containing system configuration files. This is used to provide alternate configuration when testing and should not need to be changed from the default. Default is /etc. CTDB_INIT_STYLE=debian|redhat|suse This is the init style used by the Linux distribution (or other operating system) being used. This is usually determined dynamically by checking the system. This variable is used by the initscript to determine which init system primitives to use. It is also used by some eventscripts to choose the name of initscripts for certain services, since these can vary between distributions. No fixed default. If this option needs to be changed from the calculated default for the initscript to function properly, then it must be set in the distribution-specific initscript configuration, such as /etc/sysconfig/ctdb CTDB_MAX_CORRUPT_DB_BACKUPS=NUM NUM is the maximum number of volatile TDB database backups to be kept (for each database) when a corrupt database is found during startup. Volatile TDBs are zeroed during startup so backups are needed to debug any corruption that occurs before a restart. Default is 10. CTDB_RC_LOCAL=FILENAME FILENAME is a script fragment to be sourced by the functions that is sourced by scripts. On example use would be to override function definitions in unit tests. As a sanity check, this file must be executable for it to be used. No default. CTDB_RUN_TIMEOUT_MONITOR=yes|no Whether CTDB should simulate timing out monitor events. This uses the 99.timeout eventscript. Default is no. CTDB_SCRIPT_DEBUGLEVEL=NUM NUM is the level debugging messages printed by CTDB scripts. Setting this to a higher number (e.g. 4) will cause some scripts to log more messages. Default is 2. CTDB_SUPPRESS_COREFILE=yes|no Whether CTDB core files should be suppressed. Default is no. CTDB_VALGRIND=yes|no|COMMAND If "yes", this causes ctdbd 1 to be run under valgrind 1 with logs going to /var/log/ctdb_valgrind. If neither "yes" nor "no" then the value is assumed to be a COMMAND (e.g. a valgrind variation, a gdb 1 command) that is used in place of the default valgrind command. In either case, the option is passed to ctdbd. Default is no. FILES /etc/ctdb/ctdbd.conf /etc/sysconfig/ctdb /etc/default/ctdb /etc/ctdb/sysconfig/ctdb SEE ALSO ctdbd 1, ctdbd_wrapper 1, onnode 1, ctdb 7, ctdb-tunables 7, This documentation was written by Amitay Isaacs, Martin Schwenke 2007 Andrew Tridgell Ronnie Sahlberg This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb-2.5.1.dfsg/doc/ctdbd.conf.5.html0000644000175000017500000011224612245332462017042 0ustar mathieumathieuctdbd.conf

Name

ctdbd.conf — CTDB daemon configuration file

DESCRIPTION

This file contains CTDB configuration variables that are affect the operation of CTDB. The default location of this file is /etc/ctdb/ctdbd.conf.

This file is a shell script (see sh(1)) but is usually limited to simple variable assignments and shell-style comments.

CTDB configuration variables are grouped into several categories below.

Variables defined in this document can also be set in a distribution-specific configuration file such as /etc/sysconfig/ctdb (Red Hat) or /etc/default/ctdb (Debian). However, these files should be reserved for variables used by the initscript. A historical alternative is /etc/ctdb/sysconfig/ctdb - this is deprecated.

INITSCRIPT CONFIGURATION

Some options must be available to the initscript so they need to be set in the distribution-specific initscript configuration, such as /etc/sysconfig/ctdb or /etc/default/ctdb.

CTDB_PIDFILE=FILENAME

FILENAME is the name of the file used to contain the process ID (PID) of the main CTDB daemon when it is running. This is passed from the initscript to ctdbd_wrapper(1).

Default is /var/run/ctdb/ctdbd.pid. Corresponds to --pidfile.

GLOBAL CONFIGURATION

These options may be used in the initscripts, daemon and scripts.

CTDB_BASE=DIRECTORY

DIRECTORY containing CTDB scripts and configuration files.

CTDB_VARDIR=DIRECTORY

DIRECTORY containing CTDB files that are modified at runtime.

Defaults to /var/ctdb, unless /var/lib/ctdb already exists in which case it is used.

DAEMON CONFIGURATION

Variables in this section are processed by ctdbd_wrapper(1) and are converted into command-line arguments to ctdbd(1). Correspondence with ctdbd(1) options is shown for each variable. The the documentation for the relevant options for more details.

Many of these variables are also used by event scripts.

CTDB_CAPABILITY_LMASTER=yes|no

Defaults to yes. Corresponds to --no-lmaster.

CTDB_CAPABILITY_RECMASTER=yes|no

Defaults to yes. Corresponds to --no-recmaster.

CTDB_DBDIR=DIRECTORY

Defaults to CTDB_VARDIR. Corresponds to --dbdir.

CTDB_DBDIR_PERSISTENT=DIRECTORY

Defaults to CTDB_VARDIR/persistent. Corresponds to --dbdir-persistent.

CTDB_DBDIR_STATE=DIRECTORY

Defaults to CTDB_VARDIR/state. Corresponds to --dbdir-state.

CTDB_DEBUGLEVEL=DEBUGLEVEL

Default is ERR (0). Corresponds to -d or --debug.

CTDB_EVENT_SCRIPT_DIR=DIRECTORY

Default is CTDB_BASE/events.d, so usually /etc/ctdb/events.d. Corresponds to --event-script-dir.

CTDB_LOGFILE=FILENAME

Defaults to /var/log/log.ctdb. Corresponds to --logfile. See also CTDB_SYSLOG.

CTDB_LOG_RINGBUF_SIZE=NUM

Default is 0. Corresponds to --log-ringbuf-size.

CTDB_LVS_PUBLIC_IP=IPADDR

No default. Corresponds to "--lvs --single-public-ip IPADDR".

CTDB_NODES=FILENAME

Default is CTDB_BASE/nodes, so usually /etc/ctdb/nodes. Corresponds to --nlist.

CTDB_NOTIFY_SCRIPT=FILENAME

No default, usually /etc/ctdb/notify.sh. Corresponds to --notification-script.

CTDB_MAX_PERSISTENT_CHECK_ERRORS=NUM

Default 0. Corresponds to --max-persistent-check-errors.

CTDB_PUBLIC_ADDRESSES=FILENAME

No default, usually /etc/ctdb/public_addresses. Corresponds to --public-addresses.

CTDB_PUBLIC_INTERFACE=INTERFACE

No default. Corresponds to --public-interface.

CTDB_RECOVERY_LOCK=FILENAME

Defaults to /some/place/on/shared/storage, which should be change to a useful value. Corresponds to --reclock.

CTDB_SCRIPT_LOG_LEVEL=DEBUGLEVEL

Defaults to ERR (0). Corresponds to --script-log-level.

CTDB_SOCKET=FILENAME

Defaults to /tmp/ctdb.socket. Corresponds to --socket.

If you change this then you probably want to set this in root's enviroment (perhaps in a file in /etc/profile.d) so that you can use the ctdb(1) command in a straightforward manner.

CTDB_START_AS_DISABLED=yes|no

Default is no. Corresponds to --start-as-disabled.

CTDB_START_AS_STOPPED=yes|no

Default is no. Corresponds to --start-as-stopped.

CTDB_SYSLOG=yes|no

Default is no. Corresponds to --syslog.

CTDB_TRANSPORT=tcp|infiniband

Defaults to tcp. Corresponds to --transport.

While the following variables do not translate into daemon options they are used by ctdbd_wrapper(1) when starting and stopping ctdbd(1).

CTDB_SHUTDOWN_TIMEOUT=NUM

NUM is the number of seconds to wait for ctdbd(1) to shut down gracefully before giving up and killing it.

Defaults is 30.

CTDB_STARTUP_TIMEOUT=NUM

NUM is the number of seconds to wait for ctdbd(1) complete early initialisation up to a point where it is unlikely to abort. If ctdbd doesn't complete the "setup" event before this timeout then it is killed.

Defaults is 10.

NETWORK CONFIGURATION

NAT GATEWAY

NAT gateway is used to configure fallback routing for nodes when they do not host any public IP addresses. For example, it allows unhealthy nodes to reliably communicate with external infrastructure. One node in a NAT gateway group will be designated as the NAT gateway master node and other (slave) nodes will be configured with fallback routes via the NAT gateway master node. For more information, see the NAT GATEWAY section in ctdb(7).

CTDB_NATGW_DEFAULT_GATEWAY=IPADDR

IPADDR is an alternate network gateway to use on the NAT gateway master node. A fallback default route is added via this network gateway.

No default.

CTDB_NATGW_NODES=FILENAME

FILENAME contains the list of nodes that belong to the same NAT gateway group.

File format:

IPADDR
	      

No default, usually /etc/ctdb/natgw_nodes when enabled.

CTDB_NATGW_PRIVATE_NETWORK=IPADDR/MASK

IPADDR/MASK is the private sub-network that is internally routed via the NAT gateway master node. This is usually the private network that is used for node addresses.

No default.

CTDB_NATGW_PUBLIC_IFACE=IFACE

IFACE is the network interface on which the CTDB_NATGW_PUBLIC_IP will be configured.

No default.

CTDB_NATGW_PUBLIC_IP=IPADDR/MASK

IPADDR/MASK indicates the IP address that is used for outgoing traffic (originating from CTDB_NATGW_PRIVATE_NETWORK) on the NAT gateway master node. This must not be a configured public IP address.

No default.

CTDB_NATGW_SLAVE_ONLY=yes|no

When set to "yes" a node can not be a NAT gateway master node.

Default is no.

Example

CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24
CTDB_NATGW_DEFAULT_GATEWAY=10.0.0.1
CTDB_NATGW_PUBLIC_IP=10.0.0.227/24
CTDB_NATGW_PUBLIC_IFACE=eth0
	

POLICY ROUTING

A node running CTDB may be a component of a complex network topology. In particular, public addresses may be spread across several different networks (or VLANs) and it may not be possible to route packets from these public addresses via the system's default route. Therefore, CTDB has support for policy routing via the 13.per_ip_routing eventscript. This allows routing to be specified for packets sourced from each public address. The routes are added and removed as CTDB moves public addresses between nodes.

For more information, see the POLICY ROUTING section in ctdb(7).

CTDB_PER_IP_ROUTING_CONF=FILENAME

FILENAME contains elements for constructing the desired routes for each source address.

The special FILENAME value __auto_link_local__ indicates that no configuration file is provided and that CTDB should generate reasonable link-local routes for each public IP address.

File format:

IPADDR DEST-IPADDR/MASK [GATEWAY-IPADDR]
	      

No default, usually /etc/ctdb/policy_routing when enabled.

CTDB_PER_IP_ROUTING_RULE_PREF=NUM

NUM sets the priority (or preference) for the routing rules that are added by CTDB.

This should be (strictly) greater than 0 and (strictly) less than 32766. A priority of 100 is recommended, unless this conflicts with a priority already in use on the system. See ip(8), for more details.

CTDB_PER_IP_ROUTING_TABLE_ID_LOW=LOW-NUM, CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=HIGH-NUM

CTDB determines a unique routing table number to use for the routing related to each public address. LOW-NUM and HIGH-NUM indicate the minimum and maximum routing table numbers that are used.

ip(8) uses some reserved routing table numbers below 255. Therefore, CTDB_PER_IP_ROUTING_TABLE_ID_LOW should be (strictly) greater than 255.

CTDB uses the standard file /etc/iproute2/rt_tables to maintain a mapping between the routing table numbers and labels. The label for a public address ADDR will look like ctdb.addr. This means that the associated rules and routes are easy to read (and manipulate).

No default, usually 1000 and 9000.

Example

CTDB_PER_IP_ROUTING_CONF=/etc/ctdb/policy_routing
CTDB_PER_IP_ROUTING_RULE_PREF=100
CTDB_PER_IP_ROUTING_TABLE_ID_LOW=1000
CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000
	

MISCELLANEOUS NETWORK CONFIGURATION

CTDB_PARTIALLY_ONLINE_INTERFACES=yes|no

Whether one or more offline interfaces should cause a monitor event to fail if there are other interfaces that are up. If this is "yes" and a node has some interfaces that are down then ctdb status will display the node as "PARTIALLYONLINE".

Default is "no".

SERVICE CONFIGURATION

CTDB can be configured to manage and/or monitor various NAS (and other) services via its eventscripts.

In the simplest case CTDB will manage a service. This means the service will be started and stopped along with CTDB, CTDB will monitor the service and CTDB will do any required reconfiguration of the service when public IP addresses are failed over.

SAMBA

Eventscripts

49.winbind
50.samba
CTDB_MANAGES_SAMBA=yes|no

Should CTDB manage Samba?

Default is no.

CTDB_MANAGES_WINBIND=yes|no

Should CTDB manage Winbind?

Default is no.

CTDB_SAMBA_CHECK_PORTS=PORT-LIST

When monitoring Samba, check TCP ports in space-separated PORT-LIST.

Default is to monitor ports that Samba is configured to listen on.

CTDB_SAMBA_SKIP_SHARE_CHECK=yes|no

As part of monitoring, should CTDB skip the check for the existence of each directory configured as share in Samba. This may be desirable if there is a large number of shares.

Default is no.

CTDB_SERVICE_NMB=SERVICE

Distribution specific SERVICE for managing nmbd.

Default is distribution-dependant.

CTDB_SERVICE_SMB=SERVICE

Distribution specific SERVICE for managing smbd.

Default is distribution-dependant.

CTDB_SERVICE_WINBIND=SERVICE

Distribution specific SERVICE for managing winbindd.

Default is "winbind".

NFS

This includes parameters for the kernel NFS server and the user-space NFS-Ganesha server.

Eventscripts

60.nfs
60.ganesha
CTDB_CLUSTER_FILESYSTEM_TYPE=gpfs

The type of cluster filesystem to use with NFS-ganesha. Currently only "gpfs" is supported.

Default is "gpfs".

CTDB_MANAGES_NFS=yes|no

Should CTDB manage NFS?

Default is no.

CTDB_MONITOR_NFS_THREAD_COUNT=yes|no

Whether to monitor the NFS kernel server thread count.

This works around a limitation in some NFS initscripts where some threads can be stuck in host filesystem calls (perhaps due to slow storage), a restart occurs, some threads don't exit, the start only adds the missing number of threads, the stuck threads exit, and the result is a lower than expected thread count. Note that if you must also set RPCNFSDCOUNT (RedHat/Debian) or USE_KERNEL_NFSD_NUMBER (SUSE) in your NFS configuration so the monitoring code knows how many threads there should be - if neither of these are set then this option will be ignored.

Default is no.

CTDB_NFS_DUMP_STUCK_THREADS=NUM

NUM is the number of NFS kernel server threads to dump stack traces for if some are still alive after stopping NFS during a restart.

Default is 0.

CTDB_NFS_SERVER_MODE=kernel|ganesha

Selects which NFS server to be managed.

This replaces the deprecated variable NFS_SERVER_MODE.

Default is "kernel".

CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK=yes|no

During monitoring, should CTDB skip the rpcinfo check that is used to see if the NFS kernel server is functional.

Default is no.

CTDB_NFS_SKIP_SHARE_CHECK=yes|no

As part of monitoring, should CTDB skip the check for the existence of each directory exported via NFS. This may be desirable if there is a large number of exports.

Default is no.

CTDB_RPCINFO_LOCALHOST=IPADDR|HOSTNAME

IPADDR or HOSTNAME indicates the address that rpcinfo should connect to when doing rpcinfo check on RPC service during monitoring. Optimally this would be "localhost". However, this can add some performance overheads.

Default is "127.0.0.1".

CTDB_SKIP_GANESHA_NFSD_CHECK=yes|no

As part of monitoring, should CTDB skip the check for the existence of each directory exported via NFS-Ganesha. This may be desirable if there is a large number of exports.

Default is no.

APACHE HTTPD

CTDB can manage the Apache web server.

Eventscript

41.httpd
CTDB_MANAGES_HTTPD=yes|no

Should CTDB manage the Apache web server?

Default is no.

CLAMAV

CTDB has support to manage the popular anti-virus daemon ClamAV.

Eventscript

31.clamd

This eventscript is not enabled by default. Use ctdb enablescript to enable it.

CTDB_MANAGES_CLAMD=yes|no

Should CTDB manage ClamAV?

Default is no.

CTDB_CLAMD_SOCKET=FILENAME

FILENAME is the socket to monitor ClamAV.

No default.

ISCSI

CTDB has support for managing the Linux iSCSI tgtd service.

Eventscript

70.iscsi
CTDB_MANAGES_ISCSI=yes|no

Should CTDB manage iSCSI tgtd?

Default is no.

CTDB_START_ISCSI_SCRIPTS=DIRECTORY

DIRECTORY on shared storage containing scripts to start tgtd for each public IP address.

No default.

MULTIPATHD

CTDB can monitor multipath devices to ensure that active paths are available.

Eventscript

20.multipathd

This eventscript is not enabled by default. Use ctdb enablescript to enable it.

CTDB_MONITOR_MPDEVICES=MP-DEVICE-LIST

MP-DEVICE-LIST is a list of multipath devices for CTDB to monitor?

No default.

VSFTPD

CTDB can manage the vsftpd FTP server.

Eventscript

40.vsftpd
CTDB_MANAGES_VSFTPD=yes|no

Should CTDB manage the vsftpd FTP server?

Default is no.

SYSTEM RESOURCE MONITORING CONFIGURATION

CTDB can experience seemingly random (performance and other) issues if system resources become too contrained. Options in this section can be enabled to allow certain system resources to be checked.

Eventscripts

00.ctdb
40.fs_use

Filesystem usage monitoring is in 40.fs_use. This eventscript is not enabled by default. Use ctdb enablescript to enable it.

CTDB_CHECK_FS_USE=FS-LIMIT-LIST

FS-LIMIT-LIST is a space-separated list of FILESYSTEM:LIMIT pairs indicating that a node should be flagged unhealthy if the space used on FILESYSTEM reaches LIMIT%.

No default.

Note that this feature uses the 40.fs_use eventscript, which is not enabled by default. Use ctdb enablescript to enable it.

CTDB_CHECK_SWAP_IS_NOT_USED=yes|no

Should a warning be logged if swap space is in use.

Default is no.

CTDB_MONITOR_FREE_MEMORY=NUM

NUM is a lower limit on available system memory, expressed in megabytes. If this is set and the amount of available memory falls below this limit then some debug information will be logged, the node will be disabled and then CTDB will be shut down.

No default.

CTDB_MONITOR_FREE_MEMORY_WARN=NUM

NUM is a lower limit on available system memory, expressed in megabytes. If this is set and the amount of available memory falls below this limit then a warning will be logged.

No default.

MISCELLANEOUS SERVICE-RELATED CONFIGURATION

CTDB_MANAGED_SERVICES=SERVICE-LIST

SERVICE-LIST is a space-separated list of SERVICEs that CTDB should manage. This can be used as an alternative to the CTDB_MANAGES_SERVICE variables.

No default.

CTDB_SERVICE_AUTOSTARTSTOP=yes|no

When CTDB should start and stop services if they become managed or unmanaged.

Default is no.

TUNABLES CONFIGURATION

CTDB tunables (see ctdbd-tunables(7)) can be set from the configuration file. They are set as follows:


CTDB_SET_TUNABLE=VALUE

For example:

CTDB_SET_MonitorInterval=20
      

DEBUG AND TEST

Variable in this section are for debugging and testing CTDB. They should not generally be needed.

CTDB_DEBUG_HUNG_SCRIPT=FILENAME

FILENAME is a script to run to log debug information when an event script times out.

Default is CTDB_BASE/debug-hung-script.sh.

CTDB_DEBUG_LOCKS=FILENAME

FILENAME is a script to run to log debug information when an CTDB fails to freeze databases during recovery.

No default, usually CTDB_BASE/debug_locks.sh.

CTDB_ETCDIR=DIRECTORY

DIRECTORY containing system configuration files. This is used to provide alternate configuration when testing and should not need to be changed from the default.

Default is /etc.

CTDB_INIT_STYLE=debian|redhat|suse

This is the init style used by the Linux distribution (or other operating system) being used. This is usually determined dynamically by checking the system. This variable is used by the initscript to determine which init system primitives to use. It is also used by some eventscripts to choose the name of initscripts for certain services, since these can vary between distributions.

No fixed default.

If this option needs to be changed from the calculated default for the initscript to function properly, then it must be set in the distribution-specific initscript configuration, such as /etc/sysconfig/ctdb

CTDB_MAX_CORRUPT_DB_BACKUPS=NUM

NUM is the maximum number of volatile TDB database backups to be kept (for each database) when a corrupt database is found during startup. Volatile TDBs are zeroed during startup so backups are needed to debug any corruption that occurs before a restart.

Default is 10.

CTDB_RC_LOCAL=FILENAME

FILENAME is a script fragment to be sourced by the functions that is sourced by scripts. On example use would be to override function definitions in unit tests. As a sanity check, this file must be executable for it to be used.

No default.

CTDB_RUN_TIMEOUT_MONITOR=yes|no

Whether CTDB should simulate timing out monitor events. This uses the 99.timeout eventscript.

Default is no.

CTDB_SCRIPT_DEBUGLEVEL=NUM

NUM is the level debugging messages printed by CTDB scripts. Setting this to a higher number (e.g. 4) will cause some scripts to log more messages.

Default is 2.

CTDB_SUPPRESS_COREFILE=yes|no

Whether CTDB core files should be suppressed.

Default is no.

CTDB_VALGRIND=yes|no|COMMAND

If "yes", this causes ctdbd(1) to be run under valgrind(1) with logs going to /var/log/ctdb_valgrind. If neither "yes" nor "no" then the value is assumed to be a COMMAND (e.g. a valgrind variation, a gdb(1) command) that is used in place of the default valgrind command. In either case, the --valgrind option is passed to ctdbd.

Default is no.

FILES

/etc/ctdb/ctdbd.conf
/etc/sysconfig/ctdb
/etc/default/ctdb
/etc/ctdb/sysconfig/ctdb

SEE ALSO

ctdbd(1), ctdbd_wrapper(1), onnode(1), ctdb(7), ctdb-tunables(7), http://ctdb.samba.org/

ctdb-2.5.1.dfsg/doc/examples/0000755000175000017500000000000012245023514015610 5ustar mathieumathieuctdb-2.5.1.dfsg/doc/examples/README0000644000175000017500000000024412245023514016470 0ustar mathieumathieuThis directory includes sample CTDB cluster configurations. o cluster.conf - Basic cluster setup o natgw.conf - Basic cluster setup with NAT gateway feature ctdb-2.5.1.dfsg/doc/examples/cluster.conf0000644000175000017500000000473212245023514020146 0ustar mathieumathieu# # CTDB configuration for simple cluster # # This is the sample configuration for a 3-node CTDB cluster providing file # services via Samba and NFS. # # Cluster details: # # internal network (192.168.1.0/24) # -------+----------------------+-----------------------+---------- # | | | # | | | # eth0 | 192.168.1.1 eth0 | 192.168.1.2 eth0 | 192.168.1.3 # +-----+-----+ +-----+-----+ +-----+-----+ # | | | | | | # | Node 1 | | Node 2 | | Node 3 | # | | | | | | # +-----+-----+ +-----+-----+ +-----+-----+ # eth1 | 10.1.1.1 eth1 | 10.1.1.2 eth1 | 10.1.1.3 # | | | # | | | # -------+----------------------+-----------------------+---------- # public network (10.1.1.0/24) # # # Storage details: # # Each node has a shared storage - /shared # # # Service details: # # Cluster provides file services on following IP addresses # # 10.1.1.101 - 10.1.1.106 # # Each node also has a fixed IP address on public network. This is used to # communicate to network infrastructure (e.g. DNS, Active Directory, ...). # Make sure that file services are not available on these fixed IP addresses # (e.g. network filtering, using cluster hostname instead of IPs) CTDB_RECOVERY_LOCK=/shared/recovery.lock # # Nodes configuration # # ---------- /etc/ctdb/nodes ---------- # 192.168.1.1 # 192.168.1.2 # 192.168.1.3 # ---------- /etc/ctdb/nodes ---------- # CTDB_NODES=/etc/ctdb/nodes # # Public addresses configuration # # ---------- /etc/ctdb/public_addresses ---------- # 10.1.1.101/24 eth1 # 10.1.1.102/24 eth1 # 10.1.1.103/24 eth1 # 10.1.1.104/24 eth1 # 10.1.1.105/24 eth1 # 10.1.1.106/24 eth1 # ---------- /etc/ctdb/public_addresses ---------- # CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses # Enable logging to syslog CTDB_SYSLOG=yes # Default log level CTDB_DEBUGLEVEL=NOTICE # Auto start/stop managed services CTDB_AUTO_STARTSTOP=yes # # Samba configuration # CTDB_MANAGES_SAMBA=yes # CTDB_SAMBA_SKIP_SHARE_CHECK=yes CTDB_MANAGES_WINBIND=yes # # NFS configuration # CTDB_MANAGES_NFS=yes CTDB_RPCINFO_LOCALHOST="127.0.0.1" # CTDB_MONITOR_NFS_THREAD_COUNT=yes ctdb-2.5.1.dfsg/doc/examples/natgw.conf0000644000175000017500000000564712245023514017613 0ustar mathieumathieu# # CTDB configuration for simple cluster with NAT gateway # # This is the sample configuration for a 3-node CTDB cluster providing file # services via Samba and NFS. # # Cluster details: # # internal network (192.168.1.0/24) # -------+----------------------+-----------------------+---------- # | | | # | | | # eth0 | 192.168.1.1 eth0 | 192.168.1.2 eth0 | 192.168.1.3 # +-----+-----+ +-----+-----+ +-----+-----+ # | | | | | | # | Node 1 | | Node 2 | | Node 3 | # | | | | | | # +-----+-----+ +-----+-----+ +-----+-----+ # eth1 | eth1 | eth1 | # | | | # | | | # -------+----------------------+-----------------------+-----+---- # public network (10.1.1.0/24) | # | 10.1.1.254 # o (router) # # Storage details: # # Each node has a shared storage - /shared # # # Service details: # # Cluster provides file services on following IP addresses # # 10.1.1.101 - 10.1.1.106 # # When a node is not hosting any IPs, it cannot connect to network # infrastructure (e.g. DNS, Active Directory, ...). # # Using NAT gateway feature of CTDB allows a node not hosting IPs to connect # to network infrastructure. CTDB_RECOVERY_LOCK=/shared/recovery.lock # # Nodes configuration # # ---------- /etc/ctdb/nodes ---------- # 192.168.1.1 # 192.168.1.2 # 192.168.1.3 # ---------- /etc/ctdb/nodes ---------- # CTDB_NODES=/etc/ctdb/nodes # # Public addresses configuration # # ---------- /etc/ctdb/public_addresses ---------- # 10.1.1.101/24 eth1 # 10.1.1.102/24 eth1 # 10.1.1.103/24 eth1 # 10.1.1.104/24 eth1 # 10.1.1.105/24 eth1 # 10.1.1.106/24 eth1 # ---------- /etc/ctdb/public_addresses ---------- # CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses # Enable logging to syslog CTDB_SYSLOG=yes # Default log level CTDB_DEBUGLEVEL=NOTICE # Auto start/stop managed services CTDB_AUTO_STARTSTOP=yes # # Samba configuration # CTDB_MANAGES_SAMBA=yes # CTDB_SAMBA_SKIP_SHARE_CHECK=yes CTDB_MANAGES_WINBIND=yes # # NFS configuration # CTDB_MANAGES_NFS=yes CTDB_RPCINFO_LOCALHOST="127.0.0.1" # CTDB_MONITOR_NFS_THREAD_COUNT=yes # # NAT gateway configuration # # ---------- /etc/ctdb/natgw_nodes ---------- # 192.168.1.1 # 192.168.1.2 # 192.168.1.3 # ---------- /etc/ctdb/natgw_nodes ---------- # CTDB_NATGW_PUBLIC_IP=10.1.1.121/24 CTDB_NATGW_PUBLIC_IFACE=eth1 CTDB_NATGW_DEFAULT_GATEWAY=10.1.1.254 CTDB_NATGW_PRIVATE_NETWORK=192.168.1.0/24 CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes ctdb-2.5.1.dfsg/doc/ctdb.1.xml0000644000175000017500000015332512245023514015600 0ustar mathieumathieu This documentation was written by Ronnie Sahlberg, Amitay Isaacs, Martin Schwenke 2007 Andrew Tridgell Ronnie Sahlberg This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb 1 ctdb CTDB - clustered TDB database ctdb CTDB management utility ctdb OPTION COMMAND COMMAND-ARGS DESCRIPTION ctdb is a utility to view and manage a CTDB cluster. The following terms are used when referring to nodes in a cluster: PNN Physical Node Number. The physical node number is an integer that describes the node in the cluster. The first node has physical node number 0. in a cluster. PNN-LIST This is either a single PNN, a comma-separate list of PNNs or "all". Commands that reference a database have a DB argument. This is either a database name, such as locking.tdb or a database ID such as "0x42fe72c5". OPTIONS -n PNN-LIST The nodes specified by PNN-LIST should be queried for the requested information. Default is to query the daemon running on the local host. -Y Produce output in machine readable form for easier parsing by scripts. Not all commands support this option. -t TIMEOUT Indicates that ctdb should wait up to TIMEOUT seconds for a response to most commands sent to the CTDB daemon. The default is 10 seconds. -T TIMELIMIT Indicates that TIMELIMIT is the maximum run time (in seconds) for the ctdb command. When TIMELIMIT is exceeded the ctdb command will terminate with an error. The default is 120 seconds. -? --help Print some help text to the screen. --usage Print useage information to the screen. -d --debug=DEBUGLEVEL Change the debug level for the command. Default is ERR (0). --socket=FILENAME Specify that FILENAME is the name of the Unix domain socket to use when connecting to the local CTDB daemon. The default is /tmp/ctdb.socket. ADMINISTRATIVE COMMANDS These are commands used to monitor and administer a CTDB cluster. pnn This command displays the PNN of the current node. xpnn This command displays the PNN of the current node without contacting the CTDB daemon. It parses the nodes file directly, so can produce unexpected output if the nodes file has been edited but has not been reloaded. status This command shows the current status of all CTDB nodes based on information from the queried node. Note: If the the queried node is INACTIVE then the status might not be current. Node status This includes the number of physical nodes and the status of each node. See ctdb 7 for information about node states. Generation The generation id is a number that indicates the current generation of a cluster instance. Each time a cluster goes through a reconfiguration or a recovery its generation id will be changed. This number does not have any particular meaning other than to keep track of when a cluster has gone through a recovery. It is a random number that represents the current instance of a ctdb cluster and its databases. The CTDB daemon uses this number internally to be able to tell when commands to operate on the cluster and the databases was issued in a different generation of the cluster, to ensure that commands that operate on the databases will not survive across a cluster database recovery. After a recovery, all old outstanding commands will automatically become invalid. Sometimes this number will be shown as "INVALID". This only means that the ctdbd daemon has started but it has not yet merged with the cluster through a recovery. All nodes start with generation "INVALID" and are not assigned a real generation id until they have successfully been merged with a cluster through a recovery. Virtual Node Number (VNN) map Consists of the number of virtual nodes and mapping from virtual node numbers to physical node numbers. Virtual nodes host CTDB databases. Only nodes that are participating in the VNN map can become lmaster or dmaster for database records. Recovery mode This is the current recovery mode of the cluster. There are two possible modes: NORMAL - The cluster is fully operational. RECOVERY - The cluster databases have all been frozen, pausing all services while the cluster awaits a recovery process to complete. A recovery process should finish within seconds. If a cluster is stuck in the RECOVERY state this would indicate a cluster malfunction which needs to be investigated. Once the recovery master detects an inconsistency, for example a node becomes disconnected/connected, the recovery daemon will trigger a cluster recovery process, where all databases are remerged across the cluster. When this process starts, the recovery master will first "freeze" all databases to prevent applications such as samba from accessing the databases and it will also mark the recovery mode as RECOVERY. When the CTDB daemon starts up, it will start in RECOVERY mode. Once the node has been merged into a cluster and all databases have been recovered, the node mode will change into NORMAL mode and the databases will be "thawed", allowing samba to access the databases again. Recovery master This is the cluster node that is currently designated as the recovery master. This node is responsible of monitoring the consistency of the cluster and to perform the actual recovery process when reqired. Only one node at a time can be the designated recovery master. Which node is designated the recovery master is decided by an election process in the recovery daemons running on each node. Example # ctdb status Number of nodes:4 pnn:0 192.168.2.200 OK (THIS NODE) pnn:1 192.168.2.201 OK pnn:2 192.168.2.202 OK pnn:3 192.168.2.203 OK Generation:1362079228 Size:4 hash:0 lmaster:0 hash:1 lmaster:1 hash:2 lmaster:2 hash:3 lmaster:3 Recovery mode:NORMAL (0) Recovery master:0 nodestatus <optional><parameter>PNN-LIST</parameter></optional> This command is similar to the status command. It displays the "node status" subset of output. The main differences are: The exit code is the bitwise-OR of the flags for each specified node, while ctdb status exits with 0 if it was able to retrieve status for all nodes. ctdb status provides status information for all nodes. ctdb nodestatus defaults to providing status for only the current node. If PNN-LIST is provided then status is given for the indicated node(s). By default, ctdb nodestatus gathers status from the local node. However, if invoked with "-n all" (or similar) then status is gathered from the given node(s). In particular ctdb nodestatus all and ctdb nodestatus -n all will produce different output. It is possible to provide 2 different nodespecs (with and without "-n") but the output is usually confusing! A common invocation in scripts is ctdb nodestatus all to check whether all nodes in a cluster are healthy. Example # ctdb nodestatus pnn:0 10.0.0.30 OK (THIS NODE) # ctdb nodestatus all Number of nodes:2 pnn:0 10.0.0.30 OK (THIS NODE) pnn:1 10.0.0.31 OK recmaster This command shows the pnn of the node which is currently the recmaster. Note: If the the queried node is INACTIVE then the status might not be current. uptime This command shows the uptime for the ctdb daemon. When the last recovery or ip-failover completed and how long it took. If the "duration" is shown as a negative number, this indicates that there is a recovery/failover in progress and it started that many seconds ago. Example # ctdb uptime Current time of node : Thu Oct 29 10:38:54 2009 Ctdbd start time : (000 16:54:28) Wed Oct 28 17:44:26 2009 Time of last recovery/failover: (000 16:53:31) Wed Oct 28 17:45:23 2009 Duration of last recovery/failover: 2.248552 seconds listnodes This command shows lists the ip addresses of all the nodes in the cluster. Example # ctdb listnodes 192.168.2.200 192.168.2.201 192.168.2.202 192.168.2.203 natgwlist Show the current NAT gateway master and the status of all nodes in the current NAT gateway group. See the NAT GATEWAY section in ctdb 7 for more details. Example # ctdb natgwlist 0 192.168.2.200 Number of nodes:4 pnn:0 192.168.2.200 OK (THIS NODE) pnn:1 192.168.2.201 OK pnn:2 192.168.2.202 OK pnn:3 192.168.2.203 OK ping This command will "ping" specified CTDB nodes in the cluster to verify that they are running. Example # ctdb ping -n all response from 0 time=0.000054 sec (3 clients) response from 1 time=0.000144 sec (2 clients) response from 2 time=0.000105 sec (2 clients) response from 3 time=0.000114 sec (2 clients) ifaces This command will display the list of network interfaces, which could host public addresses, along with their status. Example # ctdb ifaces Interfaces on node 0 name:eth5 link:up references:2 name:eth4 link:down references:0 name:eth3 link:up references:1 name:eth2 link:up references:1 # ctdb ifaces -Y :Name:LinkStatus:References: :eth5:1:2 :eth4:0:0 :eth3:1:1 :eth2:1:1 ip This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip. By default this command will ONLY show those public addresses that are known to the node itself. To see the full list of all public ips across the cluster you must use "ctdb ip -n all". Example # ctdb ip Public IPs on node 0 172.31.91.82 node[1] active[] available[eth2,eth3] configured[eth2,eth3] 172.31.91.83 node[0] active[eth3] available[eth2,eth3] configured[eth2,eth3] 172.31.91.84 node[1] active[] available[eth2,eth3] configured[eth2,eth3] 172.31.91.85 node[0] active[eth2] available[eth2,eth3] configured[eth2,eth3] 172.31.92.82 node[1] active[] available[eth5] configured[eth4,eth5] 172.31.92.83 node[0] active[eth5] available[eth5] configured[eth4,eth5] 172.31.92.84 node[1] active[] available[eth5] configured[eth4,eth5] 172.31.92.85 node[0] active[eth5] available[eth5] configured[eth4,eth5] # ctdb ip -Y :Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces: :172.31.91.82:1::eth2,eth3:eth2,eth3: :172.31.91.83:0:eth3:eth2,eth3:eth2,eth3: :172.31.91.84:1::eth2,eth3:eth2,eth3: :172.31.91.85:0:eth2:eth2,eth3:eth2,eth3: :172.31.92.82:1::eth5:eth4,eth5: :172.31.92.83:0:eth5:eth5:eth4,eth5: :172.31.92.84:1::eth5:eth4,eth5: :172.31.92.85:0:eth5:eth5:eth4,eth5: ipinfo <parameter>IP</parameter> This command will display details about the specified public addresses. Example # ctdb ipinfo 172.31.92.85 Public IP[172.31.92.85] info on node 0 IP:172.31.92.85 CurrentNode:0 NumInterfaces:2 Interface[1]: Name:eth4 Link:down References:0 Interface[2]: Name:eth5 Link:up References:2 (active) scriptstatus This command displays which scripts where run in the previous monitoring cycle and the result of each script. If a script failed with an error, causing the node to become unhealthy, the output from that script is also shown. Example # ctdb scriptstatus 7 scripts were executed last monitoring cycle 00.ctdb Status:OK Duration:0.056 Tue Mar 24 18:56:57 2009 10.interface Status:OK Duration:0.077 Tue Mar 24 18:56:57 2009 11.natgw Status:OK Duration:0.039 Tue Mar 24 18:56:57 2009 20.multipathd Status:OK Duration:0.038 Tue Mar 24 18:56:57 2009 31.clamd Status:DISABLED 40.vsftpd Status:OK Duration:0.045 Tue Mar 24 18:56:57 2009 41.httpd Status:OK Duration:0.039 Tue Mar 24 18:56:57 2009 50.samba Status:ERROR Duration:0.082 Tue Mar 24 18:56:57 2009 OUTPUT:ERROR: Samba tcp port 445 is not responding disablescript <parameter>SCRIPT</parameter> This command is used to disable an eventscript. This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'. enablescript <parameter>SCRIPT</parameter> This command is used to enable an eventscript. This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in 'scriptstatus'. listvars List all tuneable variables, except the values of the obsolete tunables like VacuumMinInterval. The obsolete tunables can be retrieved only explicitly with the "ctdb getvar" command. Example # ctdb listvars MaxRedirectCount = 3 SeqnumInterval = 1000 ControlTimeout = 60 TraverseTimeout = 20 KeepaliveInterval = 5 KeepaliveLimit = 5 RecoverTimeout = 20 RecoverInterval = 1 ElectionTimeout = 3 TakeoverTimeout = 9 MonitorInterval = 15 TickleUpdateInterval = 20 EventScriptTimeout = 30 EventScriptTimeoutCount = 1 RecoveryGracePeriod = 120 RecoveryBanPeriod = 300 DatabaseHashSize = 100001 DatabaseMaxDead = 5 RerecoveryTimeout = 10 EnableBans = 1 DeterministicIPs = 0 LCP2PublicIPs = 1 ReclockPingPeriod = 60 NoIPFailback = 0 DisableIPFailover = 0 VerboseMemoryNames = 0 RecdPingTimeout = 60 RecdFailCount = 10 LogLatencyMs = 0 RecLockLatencyMs = 1000 RecoveryDropAllIPs = 120 VerifyRecoveryLock = 1 VacuumInterval = 10 VacuumMaxRunTime = 30 RepackLimit = 10000 VacuumLimit = 5000 VacuumFastPathCount = 60 MaxQueueDropMsg = 1000000 UseStatusEvents = 0 AllowUnhealthyDBRead = 0 StatHistoryInterval = 1 DeferredAttachTO = 120 AllowClientDBAttach = 1 RecoverPDBBySeqNum = 0 getvar <parameter>NAME</parameter> Get the runtime value of a tuneable variable. Example # ctdb getvar MaxRedirectCount MaxRedirectCount = 3 setvar <parameter>NAME</parameter> <parameter>VALUE</parameter> Set the runtime value of a tuneable variable. Example: ctdb setvar MaxRedirectCount 5 lvsmaster This command shows which node is currently the LVSMASTER. The LVSMASTER is the node in the cluster which drives the LVS system and which receives all incoming traffic from clients. LVS is the mode where the entire CTDB/Samba cluster uses a single ip address for the entire cluster. In this mode all clients connect to one specific node which will then multiplex/loadbalance the clients evenly onto the other nodes in the cluster. This is an alternative to using public ip addresses. See the manpage for ctdbd for more information about LVS. lvs This command shows which nodes in the cluster are currently active in the LVS configuration. I.e. which nodes we are currently loadbalancing the single ip address across. LVS will by default only loadbalance across those nodes that are both LVS capable and also HEALTHY. Except if all nodes are UNHEALTHY in which case LVS will loadbalance across all UNHEALTHY nodes as well. LVS will never use nodes that are DISCONNECTED, STOPPED, BANNED or DISABLED. Example output: 2:10.0.0.13 3:10.0.0.14 getcapabilities This command shows the capabilities of the current node. See the CAPABILITIES section in ctdb 7 for more details. Example output: RECMASTER: YES LMASTER: YES LVS: NO NATGW: YES statistics Collect statistics from the CTDB daemon about how many calls it has served. Example # ctdb statistics CTDB version 1 num_clients 3 frozen 0 recovering 0 client_packets_sent 360489 client_packets_recv 360466 node_packets_sent 480931 node_packets_recv 240120 keepalive_packets_sent 4 keepalive_packets_recv 3 node req_call 2 reply_call 2 req_dmaster 0 reply_dmaster 0 reply_error 0 req_message 42 req_control 120408 reply_control 360439 client req_call 2 req_message 24 req_control 360440 timeouts call 0 control 0 traverse 0 total_calls 2 pending_calls 0 lockwait_calls 0 pending_lockwait_calls 0 memory_used 5040 max_hop_count 0 max_call_latency 4.948321 sec max_lockwait_latency 0.000000 sec statisticsreset This command is used to clear all statistics counters in a node. Example: ctdb statisticsreset dbstatistics <parameter>DB</parameter> Display statistics about the database DB. Example # ctdb dbstatistics locking.tdb DB Statistics: locking.tdb ro_delegations 0 ro_revokes 0 locks total 14356 failed 0 current 0 pending 0 hop_count_buckets: 28087 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 lock_buckets: 0 14188 38 76 32 19 3 0 0 0 0 0 0 0 0 0 locks_latency MIN/AVG/MAX 0.001066/0.012686/4.202292 sec out of 14356 Num Hot Keys: 1 Count:8 Key:ff5bd7cb3ee3822edc1f0000000000000000000000000000 getreclock This command is used to show the filename of the reclock file that is used. Example output: Reclock file:/gpfs/.ctdb/shared setreclock [filename] This command is used to modify, or clear, the file that is used as the reclock file at runtime. When this command is used, the reclock file checks are disabled. To re-enable the checks the administrator needs to activate the "VerifyRecoveryLock" tunable using "ctdb setvar". If run with no parameter this will remove the reclock file completely. If run with a parameter the parameter specifies the new filename to use for the recovery lock. This command only affects the runtime settings of a ctdb node and will be lost when ctdb is restarted. For persistent changes to the reclock file setting you must edit /etc/sysconfig/ctdb. getdebug Get the current debug level for the node. the debug level controls what information is written to the log file. The debug levels are mapped to the corresponding syslog levels. When a debug level is set, only those messages at that level and higher levels will be printed. The list of debug levels from highest to lowest are : EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG setdebug <parameter>DEBUGLEVEL</parameter> Set the debug level of a node. This controls what information will be logged. The debuglevel is one of EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG getpid This command will return the process id of the ctdb daemon. disable This command is used to administratively disable a node in the cluster. A disabled node will still participate in the cluster and host clustered TDB records but its public ip address has been taken over by a different node and it no longer hosts any services. enable Re-enable a node that has been administratively disabled. stop This command is used to administratively STOP a node in the cluster. A STOPPED node is connected to the cluster but will not host any public ip addresse, nor does it participate in the VNNMAP. The difference between a DISABLED node and a STOPPED node is that a STOPPED node does not host any parts of the database which means that a recovery is required to stop/continue nodes. continue Re-start a node that has been administratively stopped. addip <parameter>IPADDR</parameter>/<parameter>mask</parameter> <parameter>IFACE</parameter> This command is used to add a new public ip to a node during runtime. This allows public addresses to be added to a cluster without having to restart the ctdb daemons. Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read. If you want this change to be permanent you must also update the public addresses file manually. delip <parameter>IPADDR</parameter> This command is used to remove a public ip from a node during runtime. If this public ip is currently hosted by the node it being removed from, the ip will first be failed over to another node, if possible, before it is removed. Note that this only updates the runtime instance of ctdb. Any changes will be lost next time ctdb is restarted and the public addresses file is re-read. If you want this change to be permanent you must also update the public addresses file manually. moveip <parameter>IPADDR</parameter> <parameter>PNN</parameter> This command can be used to manually fail a public ip address to a specific node. In order to manually override the "automatic" distribution of public ip addresses that ctdb normally provides, this command only works when you have changed the tunables for the daemon to: DeterministicIPs = 0 NoIPFailback = 1 shutdown This command will shutdown a specific CTDB daemon. setlmasterrole on|off This command is used ot enable/disable the LMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an LMASTER for records in the database. A node that does not have the LMASTER capability will not show up in the vnnmap. Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command. Once this setting has been enabled/disabled, you need to perform a recovery for it to take effect. See also "ctdb getcapabilities" setrecmasterrole on|off This command is used ot enable/disable the RECMASTER capability for a node at runtime. This capability determines whether or not a node can be used as an RECMASTER for the cluster. A node that does not have the RECMASTER capability can not win a recmaster election. A node that already is the recmaster for the cluster when the capability is stripped off the node will remain the recmaster until the next cluster election. Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command. See also "ctdb getcapabilities" reloadnodes This command is used when adding new nodes, or removing existing nodes from an existing cluster. Procedure to add a node: 1, To expand an existing cluster, first ensure with 'ctdb status' that all nodes are up and running and that they are all healthy. Do not try to expand a cluster unless it is completely healthy! 2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last entry to the file. The new node MUST be added to the end of this file! 3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node! 4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile. 5, Use 'ctdb status' on all nodes and verify that they now show the additional node. 6, Install and configure the new node and bring it online. Procedure to remove a node: 1, To remove a node from an existing cluster, first ensure with 'ctdb status' that all nodes, except the node to be deleted, are up and running and that they are all healthy. Do not try to remove a node from a cluster unless the cluster is completely healthy! 2, Shutdown and poweroff the node to be removed. 3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed. Do not delete the line for that node, just comment it out by adding a '#' at the beginning of the line. 4, Run 'ctdb reloadnodes' to force all nodes to reload the nodesfile. 5, Use 'ctdb status' on all nodes and verify that the deleted node no longer shows up in the list.. reloadips <optional><parameter>PNN-LIST</parameter></optional> This command reloads the public addresses configuration file on the specified nodes. When it completes addresses will be reconfigured and reassigned across the cluster as necessary. getdbmap This command lists all clustered TDB databases that the CTDB daemon has attached to. Some databases are flagged as PERSISTENT, this means that the database stores data persistently and the data will remain across reboots. One example of such a database is secrets.tdb where information about how the cluster was joined to the domain is stored. If a PERSISTENT database is not in a healthy state the database is flagged as UNHEALTHY. If there's at least one completely healthy node running in the cluster, it's possible that the content is restored by a recovery run automaticly. Otherwise an administrator needs to analyze the problem. See also "ctdb getdbstatus", "ctdb backupdb", "ctdb restoredb", "ctdb dumpbackup", "ctdb wipedb", "ctdb setvar AllowUnhealthyDBRead 1" and (if samba or tdb-utils are installed) "tdbtool check". Most databases are not persistent and only store the state information that the currently running samba daemons need. These databases are always wiped when ctdb/samba starts and when a node is rebooted. Example # ctdb getdbmap Number of databases:10 dbid:0x435d3410 name:notify.tdb path:/var/ctdb/notify.tdb.0 dbid:0x42fe72c5 name:locking.tdb path:/var/ctdb/locking.tdb.0 dbid:0x1421fb78 name:brlock.tdb path:/var/ctdb/brlock.tdb.0 dbid:0x17055d90 name:connections.tdb path:/var/ctdb/connections.tdb.0 dbid:0xc0bdde6a name:sessionid.tdb path:/var/ctdb/sessionid.tdb.0 dbid:0x122224da name:test.tdb path:/var/ctdb/test.tdb.0 dbid:0x2672a57f name:idmap2.tdb path:/var/ctdb/persistent/idmap2.tdb.0 PERSISTENT dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT dbid:0xe98e08b6 name:group_mapping.tdb path:/var/ctdb/persistent/group_mapping.tdb.0 PERSISTENT dbid:0x7bbbd26c name:passdb.tdb path:/var/ctdb/persistent/passdb.tdb.0 PERSISTENT # ctdb getdbmap # example for unhealthy database Number of databases:1 dbid:0xb775fff6 name:secrets.tdb path:/var/ctdb/persistent/secrets.tdb.0 PERSISTENT UNHEALTHY # ctdb -Y getdbmap :ID:Name:Path:Persistent:Unhealthy: :0x7bbbd26c:passdb.tdb:/var/ctdb/persistent/passdb.tdb.0:1:0: backupdb <parameter>DB</parameter> <parameter>FILE</parameter> Copy the contents of database DB to FILE. FILE can later be read back using restoredb. This is mainly useful for backing up persistent databases such as secrets.tdb and similar. restoredb <parameter>FILE</parameter> <optional><parameter>DB</parameter></optional> This command restores a persistent database that was previously backed up using backupdb. By default the data will be restored back into the same database as it was created from. By specifying dbname you can restore the data into a different database. getlog [<parameter>LEVEL</parameter>] [recoverd] In addition to the normal logging to a log file, CTDB also keeps a in-memory ringbuffer containing the most recent log entries for all log levels (except DEBUG). This is useful since it allows for keeping continuous logs to a file at a reasonable non-verbose level, but shortly after an incident has occured, a much more detailed log can be pulled from memory. This can allow you to avoid having to reproduce an issue due to the on-disk logs being of insufficient detail. This command extracts all messages of level or lower log level from memory and prints it to the screen. The level is not specified it defaults to NOTICE. By default, logs are extracted from the main CTDB daemon. If the recoverd option is given then logs are extracted from the recovery daemon. clearlog [recoverd] This command clears the in-memory logging ringbuffer. By default, logs are cleared in the main CTDB daemon. If the recoverd option is given then logs are cleared in the recovery daemon. setdbreadonly <parameter>DB</parameter> This command will enable the read-only record support for a database. This is an experimental feature to improve performance for contended records primarily in locking.tdb and brlock.tdb. When enabling this feature you must set it on all nodes in the cluster. setdbsticky <parameter>DB</parameter> This command will enable the sticky record support for the specified database. This is an experimental feature to improve performance for contended records primarily in locking.tdb and brlock.tdb. When enabling this feature you must set it on all nodes in the cluster. INTERNAL COMMANDS Internal commands are used by CTDB's scripts and are not required for managing a CTDB cluster. Their parameters and behaviour are subject to change. gettickles <parameter>IPADDR</parameter> Show TCP connections that are registered with CTDB to be "tickled" if there is a failover. gratiousarp <parameter>IPADDR</parameter> <parameter>INTERFACE</parameter> Send out a gratious ARP for the specified interface through the specified interface. This command is mainly used by the ctdb eventscripts. killtcp Read a list of TCP connections, one per line, from standard input and terminate each connection. A connection is specified as: SRC-IPADDR:SRC-PORT DST-IPADDR:DST-PORT Each connection is terminated by issuing a TCP RST to the SRC-IPADDR:SRC-PORT endpoint. A single connection can be specified on the command-line rather than on standard input. pdelete <parameter>DB</parameter> <parameter>KEY</parameter> Delete KEY from DB. pfetch <parameter>DB</parameter> <parameter>KEY</parameter> Print the value associated with KEY in DB. pstore <parameter>DB</parameter> <parameter>KEY</parameter> <parameter>FILE</parameter> Store KEY in DB with contents of FILE as the associated value. ptrans <parameter>DB</parameter> <optional><parameter>FILE</parameter></optional> Read a list of key-value pairs, one per line from FILE, and store them in DB using a single transaction. An empty value is equivalent to deleting the given key. The key and value should be separated by spaces or tabs. Each key/value should be a printable string enclosed in double-quotes. runstate [setup|first_recovery|startup|running] Print the runstate of the specified node. Runstates are used to serialise important state transitions in CTDB, particularly during startup. If one or more optional runstate arguments are specified then the node must be in one of these runstates for the command to succeed. Example # ctdb runstate RUNNING setifacelink <parameter>IFACE</parameter> up|down Set the internal state of network interface IFACE. This is typically used in the 10.interface script in the "monitor" event. Example: ctdb setifacelink eth0 up setnatgwstate on|off Enable or disable the NAT gateway master capability on a node. tickle <parameter>SRC-IPADDR</parameter>:<parameter>SRC-PORT</parameter> <parameter>DST-IPADDR</parameter>:<parameter>DST-PORT</parameter> Send a TCP tickle to the source host for the specified TCP connection. A TCP tickle is a TCP ACK packet with an invalid sequence and acknowledge number and will when received by the source host result in it sending an immediate correct ACK back to the other end. TCP tickles are useful to "tickle" clients after a IP failover has occured since this will make the client immediately recognize the TCP connection has been disrupted and that the client will need to reestablish. This greatly speeds up the time it takes for a client to detect and reestablish after an IP failover in the ctdb cluster. version Display the CTDB version. DEBUGGING COMMANDS These commands are primarily used for CTDB development and testing and should not be used for normal administration. OPTIONS --print-emptyrecords This enables printing of empty records when dumping databases with the catdb, cattbd and dumpdbbackup commands. Records with empty data segment are considered deleted by ctdb and cleaned by the vacuuming mechanism, so this switch can come in handy for debugging the vacuuming behaviour. --print-datasize This lets database dumps (catdb, cattdb, dumpdbbackup) print the size of the record data instead of dumping the data contents. --print-lmaster This lets catdb print the lmaster for each record. --print-hash This lets database dumps (catdb, cattdb, dumpdbbackup) print the hash for each record. --print-recordflags This lets catdb and dumpdbbackup print the record flags for each record. Note that cattdb always prints the flags. process-exists <parameter>PID</parameter> This command checks if a specific process exists on the CTDB host. This is mainly used by Samba to check if remote instances of samba are still running or not. getdbstatus <parameter>DB</parameter> This command displays more details about a database. Example # ctdb getdbstatus test.tdb.0 dbid: 0x122224da name: test.tdb path: /var/ctdb/test.tdb.0 PERSISTENT: no HEALTH: OK # ctdb getdbstatus registry.tdb # with a corrupted TDB dbid: 0xf2a58948 name: registry.tdb path: /var/ctdb/persistent/registry.tdb.0 PERSISTENT: yes HEALTH: NO-HEALTHY-NODES - ERROR - Backup of corrupted TDB in '/var/ctdb/persistent/registry.tdb.0.corrupted.20091208091949.0Z' catdb <parameter>DB</parameter> Print a dump of the clustered TDB database DB. cattdb <parameter>DB</parameter> Print a dump of the contents of the local TDB database DB. dumpdbbackup <parameter>FILE</parameter> Print a dump of the contents from database backup FILE, similar to catdb. wipedb <parameter>DB</parameter> Remove all contents of database DB. recover This command will trigger the recovery daemon to do a cluster recovery. ipreallocate, sync This command will force the recovery master to perform a full ip reallocation process and redistribute all ip addresses. This is useful to "reset" the allocations back to its default state if they have been changed using the "moveip" command. While a "recover" will also perform this reallocation, a recovery is much more hevyweight since it will also rebuild all the databases. getmonmode This command returns the monutoring mode of a node. The monitoring mode is either ACTIVE or DISABLED. Normally a node will continuously monitor that all other nodes that are expected are in fact connected and that they respond to commands. ACTIVE - This is the normal mode. The node is actively monitoring all other nodes, both that the transport is connected and also that the node responds to commands. If a node becomes unavailable, it will be marked as DISCONNECTED and a recovery is initiated to restore the cluster. DISABLED - This node is not monitoring that other nodes are available. In this mode a node failure will not be detected and no recovery will be performed. This mode is useful when for debugging purposes one wants to attach GDB to a ctdb process but wants to prevent the rest of the cluster from marking this node as DISCONNECTED and do a recovery. setmonmode 0|1 This command can be used to explicitly disable/enable monitoring mode on a node. The main purpose is if one wants to attach GDB to a running ctdb daemon but wants to prevent the other nodes from marking it as DISCONNECTED and issuing a recovery. To do this, set monitoring mode to 0 on all nodes before attaching with GDB. Remember to set monitoring mode back to 1 afterwards. attach <parameter>DBNAME</parameter> [persistent] This is a debugging command. This command will make the CTDB daemon create a new CTDB database and attach to it. dumpmemory This is a debugging command. This command will make the ctdb daemon to write a fill memory allocation map to standard output. rddumpmemory This is a debugging command. This command will dump the talloc memory allocation tree for the recovery daemon to standard output. thaw Thaw a previously frozen node. eventscript <parameter>ARGUMENTS</parameter> This is a debugging command. This command can be used to manually invoke and run the eventscritps with arbitrary arguments. ban <parameter>BANTIME</parameter> Administratively ban a node for BANTIME seconds. The node will be unbanned after BANTIME seconds have elapsed. A banned node does not participate in the cluster. It does not host any records for the clustered TDB and does not host any public IP addresses. Nodes are automatically banned if they misbehave. For example, a node may be banned if it causes too many cluster recoveries. To administratively exclude a node from a cluster use the stop command. unban This command is used to unban a node that has either been administratively banned using the ban command or has been automatically banned. rebalancenode <optional><parameter>PNN-LIST</parameter></optional> This command marks the given nodes as rebalance targets in the LCP2 IP allocation algorithm. The reloadips command will do this as necessary so this command should not be needed. check_srvids <parameter>SRVID</parameter> ... This command checks whether a set of srvid message ports are registered on the node or not. The command takes a list of values to check. Example # ctdb check_srvids 1 2 3 14765 Server id 0:1 does not exist Server id 0:2 does not exist Server id 0:3 does not exist Server id 0:14765 exists vacuum [<parameter>max-records</parameter>] Over time CTDB databases will fill up with empty deleted records which will lead to a progressive slow down of CTDB database access. This command is used to prune all databases and delete all empty records from the cluster. By default, vacuum will delete all empty records from all databases. If [max_records] is specified, the command will only delete the first [max_records] empty records for each database. Vacuum only deletes records where the local node is the lmaster. To delete all records from the entire cluster you need to run a vacuum from each node. This command is not disruptive. Samba is unaffected and will still be able to read/write records normally while the database is being vacuumed. Example: ctdb vacuum By default, this operation is issued from the 00.ctdb event script every 5 minutes. repack [max_freelist] Over time, when records are created and deleted in a TDB, the TDB list of free space will become fragmented. This can lead to a slowdown in accessing TDB records. This command is used to defragment a TDB database and pruning the freelist. If [max_freelist] is specified, then a database will only be repacked if it has more than this number of entries in the freelist. During repacking of the database, the entire TDB database will be locked to prevent writes. If samba tries to write to a record in the database during a repack operation, samba will block until the repacking has completed. This command can be disruptive and can cause samba to block for the duration of the repack operation. In general, a repack operation will take less than one second to complete. A repack operation will only defragment the local TDB copy of the CTDB database. You need to run this command on all of the nodes to repack a CTDB database completely. Example: ctdb repack 1000 By default, this operation is issued from the 00.ctdb event script every 5 minutes. SEE ALSO ctdbd 1, onnode 1, ctdb 7, ctdb-tunables 7, ctdb-2.5.1.dfsg/doc/onnode.10000644000175000017500000001554012245332460015346 0ustar mathieumathieu'\" t .\" Title: onnode .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "ONNODE" "1" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" onnode \- run commands on CTDB cluster nodes .SH "SYNOPSIS" .HP \w'\fBonnode\fR\ 'u \fBonnode\fR [\fIOPTION\fR...] {\fINODES\fR} {\fICOMMAND\fR} .SH "DESCRIPTION" .PP onnode is a utility to run commands on a specific node of a CTDB cluster, or on all nodes\&. .PP \fINODES\fR specifies which node(s) to run a command on\&. See section NODES SPECIFICATION for details\&. .PP \fICOMMAND\fR can be any shell command\&. The onnode utility uses ssh or rsh to connect to the remote nodes and run the command\&. .SH "OPTIONS" .PP \-c .RS 4 Execute COMMAND in the current working directory on the specified nodes\&. .RE .PP \-f \fIFILENAME\fR .RS 4 Specify an alternative nodes FILENAME to use instead of the default\&. This option overrides the CTDB_NODES_FILE environment variable\&. See the discussion of /etc/ctdb/nodes in the FILES section for more details\&. .RE .PP \-i .RS 4 Keep standard input open, allowing data to be piped to onnode\&. Normally onnode closes stdin to avoid surprises when scripting\&. Note that this option is ignored when using \fB\-p\fR or if \fBSSH\fR is set to anything other than "ssh"\&. .RE .PP \-n .RS 4 Allow nodes to be specified by name rather than node numbers\&. These nodes don\*(Aqt need to be listed in the nodes file\&. You can avoid the nodes file entirely by combining this with \-f /dev/null\&. .RE .PP \-o \fIPREFIX\fR .RS 4 Causes standard output from each node to be saved into a file with name PREFIX\&.\fIIP\fR\&. .RE .PP \-p .RS 4 Run COMMAND in parallel on the specified nodes\&. The default is to run COMMAND sequentially on each node\&. .RE .PP \-P .RS 4 Push files to nodes\&. Names of files to push are specified rather than the usual command\&. Quoting is fragile/broken \- filenames with whitespace in them are not supported\&. .RE .PP \-q .RS 4 Do not print node addresses\&. Normally, onnode prints informational node addresses if more than one node is specified\&. This overrides \-v\&. .RE .PP \-v .RS 4 Print node addresses even if only one node is specified\&. Normally, onnode prints informational node addresses when more than one node is specified\&. .RE .PP \-h, \-\-help .RS 4 Show a short usage guide\&. .RE .SH "NODES SPECIFICATION" .PP Nodes can be specified via numeric node numbers (from 0 to N\-1) or mnemonics\&. Multiple nodes are specified using lists of nodes, separated by commas, and ranges of numeric node numbers, separated by dashes\&. If nodes are specified multiple times then the command will be executed multiple times on those nodes\&. The order of nodes is significant\&. .PP The following mnemonics are available: .PP all .RS 4 All nodes\&. .RE .PP any .RS 4 A node where ctdbd is running\&. This semi\-random but there is a bias towards choosing a low numbered node\&. .RE .PP ok | healthy .RS 4 All nodes that are not disconnected, banned, disabled or unhealthy\&. .RE .PP con | connected .RS 4 All nodes that are not disconnected\&. .RE .PP lvs | lvsmaster .RS 4 The current LVS master\&. .RE .PP natgw | natgwlist .RS 4 The current NAT gateway\&. .RE .PP rm | recmaster .RS 4 The current recovery master\&. .RE .SH "EXAMPLES" .PP The following command would show the process ID of ctdbd on all nodes .sp .if n \{\ .RS 4 .\} .nf onnode all ctdb getpid .fi .if n \{\ .RE .\} .PP The following command would show the last 5 lines of log on each node, preceded by the node\*(Aqs hostname .sp .if n \{\ .RS 4 .\} .nf onnode all "hostname; tail \-5 /var/log/log\&.ctdb" .fi .if n \{\ .RE .\} .PP The following command would restart the ctdb service on all nodes, in parallel\&. .sp .if n \{\ .RS 4 .\} .nf onnode \-p all service ctdb restart .fi .if n \{\ .RE .\} .PP The following command would run \&./foo in the current working directory, in parallel, on nodes 0, 2, 3 and 4\&. .sp .if n \{\ .RS 4 .\} .nf onnode \-c \-p 0,2\-4 \&./foo .fi .if n \{\ .RE .\} .SH "ENVIRONMENT" .PP \fBCTDB_BASE\fR .RS 4 Directory containing CTDB configuration files\&. The default is /etc/ctdb\&. .RE .PP \fBCTDB_NODES_FILE\fR .RS 4 Name of alternative nodes file to use instead of the default\&. See the FILES section for more details\&. .RE .SH "FILES" .PP /etc/ctdb/nodes .RS 4 Default file containing a list of each node\*(Aqs IP address or hostname\&. .sp Actually, the default is $CTDB_BASE/nodes, where \fBCTDB_BASE\fR defaults to /etc/ctdb\&. If a relative path is given (via the \-f option or \fBCTDB_BASE\fR) and no corresponding file exists relative to the current directory then the file is also searched for in the $CTDB_BASE directory\&. .RE .PP /etc/ctdb/onnode\&.conf .RS 4 If this file exists it is sourced by onnode\&. The main purpose is to allow the administrator to set \fBSSH\fR to something other than "ssh"\&. In this case the \-t option is ignored\&. For example, the administrator may choose to use use rsh instead of ssh\&. .RE .SH "SEE ALSO" .PP \fBctdb\fR(7), \m[blue]\fB\%http://ctdb.samba.org/\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Andrew Tridgell, Martin Schwenke .SH "COPYRIGHT" .br Copyright \(co 2007 Andrew Tridgell, Ronnie Sahlberg .br Copyright \(co 2008 Martin Schwenke .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp ctdb-2.5.1.dfsg/doc/ctdbd.conf.50000644000175000017500000006046612245332462016105 0ustar mathieumathieu'\" t .\" Title: ctdbd.conf .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "CTDBD\&.CONF" "5" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ctdbd.conf \- CTDB daemon configuration file .SH "DESCRIPTION" .PP This file contains CTDB configuration variables that are affect the operation of CTDB\&. The default location of this file is /etc/ctdb/ctdbd\&.conf\&. .PP This file is a shell script (see \fBsh\fR(1)) but is usually limited to simple variable assignments and shell\-style comments\&. .PP CTDB configuration variables are grouped into several categories below\&. .PP Variables defined in this document can also be set in a distribution\-specific configuration file such as /etc/sysconfig/ctdb (Red Hat) or /etc/default/ctdb (Debian)\&. However, these files should be reserved for variables used by the initscript\&. A historical alternative is /etc/ctdb/sysconfig/ctdb \- this is deprecated\&. .SH "INITSCRIPT CONFIGURATION" .PP Some options must be available to the initscript so they need to be set in the distribution\-specific initscript configuration, such as /etc/sysconfig/ctdb or /etc/default/ctdb\&. .PP CTDB_PIDFILE=\fIFILENAME\fR .RS 4 FILENAME is the name of the file used to contain the process ID (PID) of the main CTDB daemon when it is running\&. This is passed from the initscript to \fBctdbd_wrapper\fR(1)\&. .sp Default is /var/run/ctdb/ctdbd\&.pid\&. Corresponds to \fB\-\-pidfile\fR\&. .RE .SH "GLOBAL CONFIGURATION" .PP These options may be used in the initscripts, daemon and scripts\&. .PP CTDB_BASE=\fIDIRECTORY\fR .RS 4 DIRECTORY containing CTDB scripts and configuration files\&. .RE .PP CTDB_VARDIR=\fIDIRECTORY\fR .RS 4 DIRECTORY containing CTDB files that are modified at runtime\&. .sp Defaults to /var/ctdb, unless /var/lib/ctdb already exists in which case it is used\&. .RE .SH "DAEMON CONFIGURATION" .PP Variables in this section are processed by \fBctdbd_wrapper\fR(1) and are converted into command\-line arguments to \fBctdbd\fR(1)\&. Correspondence with \fBctdbd\fR(1) options is shown for each variable\&. The the documentation for the relevant options for more details\&. .PP Many of these variables are also used by event scripts\&. .PP CTDB_CAPABILITY_LMASTER=yes|no .RS 4 Defaults to yes\&. Corresponds to \fB\-\-no\-lmaster\fR\&. .RE .PP CTDB_CAPABILITY_RECMASTER=yes|no .RS 4 Defaults to yes\&. Corresponds to \fB\-\-no\-recmaster\fR\&. .RE .PP CTDB_DBDIR=\fIDIRECTORY\fR .RS 4 Defaults to \fICTDB_VARDIR\fR\&. Corresponds to \fB\-\-dbdir\fR\&. .RE .PP CTDB_DBDIR_PERSISTENT=\fIDIRECTORY\fR .RS 4 Defaults to \fICTDB_VARDIR\fR/persistent\&. Corresponds to \fB\-\-dbdir\-persistent\fR\&. .RE .PP CTDB_DBDIR_STATE=\fIDIRECTORY\fR .RS 4 Defaults to \fICTDB_VARDIR\fR/state\&. Corresponds to \fB\-\-dbdir\-state\fR\&. .RE .PP CTDB_DEBUGLEVEL=\fIDEBUGLEVEL\fR .RS 4 Default is ERR (0)\&. Corresponds to \fB\-d\fR or \fB\-\-debug\fR\&. .RE .PP CTDB_EVENT_SCRIPT_DIR=\fIDIRECTORY\fR .RS 4 Default is \fICTDB_BASE\fR/events\&.d, so usually /etc/ctdb/events\&.d\&. Corresponds to \fB\-\-event\-script\-dir\fR\&. .RE .PP CTDB_LOGFILE=\fIFILENAME\fR .RS 4 Defaults to /var/log/log\&.ctdb\&. Corresponds to \fB\-\-logfile\fR\&. See also CTDB_SYSLOG\&. .RE .PP CTDB_LOG_RINGBUF_SIZE=\fINUM\fR .RS 4 Default is 0\&. Corresponds to \fB\-\-log\-ringbuf\-size\fR\&. .RE .PP CTDB_LVS_PUBLIC_IP=\fIIPADDR\fR .RS 4 No default\&. Corresponds to "\fB\-\-lvs\fR\fB\-\-single\-public\-ip IPADDR"\fR\&. .RE .PP CTDB_NODES=\fIFILENAME\fR .RS 4 Default is \fICTDB_BASE\fR/nodes, so usually /etc/ctdb/nodes\&. Corresponds to \fB\-\-nlist\fR\&. .RE .PP CTDB_NOTIFY_SCRIPT=\fIFILENAME\fR .RS 4 No default, usually /etc/ctdb/notify\&.sh\&. Corresponds to \fB\-\-notification\-script\fR\&. .RE .PP CTDB_MAX_PERSISTENT_CHECK_ERRORS=\fINUM\fR .RS 4 Default 0\&. Corresponds to \fB\-\-max\-persistent\-check\-errors\fR\&. .RE .PP CTDB_PUBLIC_ADDRESSES=\fIFILENAME\fR .RS 4 No default, usually /etc/ctdb/public_addresses\&. Corresponds to \fB\-\-public\-addresses\fR\&. .RE .PP CTDB_PUBLIC_INTERFACE=\fIINTERFACE\fR .RS 4 No default\&. Corresponds to \fB\-\-public\-interface\fR\&. .RE .PP CTDB_RECOVERY_LOCK=\fIFILENAME\fR .RS 4 Defaults to /some/place/on/shared/storage, which should be change to a useful value\&. Corresponds to \fB\-\-reclock\fR\&. .RE .PP CTDB_SCRIPT_LOG_LEVEL=\fIDEBUGLEVEL\fR .RS 4 Defaults to ERR (0)\&. Corresponds to \fB\-\-script\-log\-level\fR\&. .RE .PP CTDB_SOCKET=\fIFILENAME\fR .RS 4 Defaults to /tmp/ctdb\&.socket\&. Corresponds to \fB\-\-socket\fR\&. .sp If you change this then you probably want to set this in root\*(Aqs enviroment (perhaps in a file in /etc/profile\&.d) so that you can use the \fBctdb\fR(1) command in a straightforward manner\&. .RE .PP CTDB_START_AS_DISABLED=yes|no .RS 4 Default is no\&. Corresponds to \fB\-\-start\-as\-disabled\fR\&. .RE .PP CTDB_START_AS_STOPPED=yes|no .RS 4 Default is no\&. Corresponds to \fB\-\-start\-as\-stopped\fR\&. .RE .PP CTDB_SYSLOG=yes|no .RS 4 Default is no\&. Corresponds to \fB\-\-syslog\fR\&. .RE .PP CTDB_TRANSPORT=tcp|infiniband .RS 4 Defaults to tcp\&. Corresponds to \fB\-\-transport\fR\&. .RE .PP While the following variables do not translate into daemon options they are used by \fBctdbd_wrapper\fR(1) when starting and stopping \fBctdbd\fR(1)\&. .PP CTDB_SHUTDOWN_TIMEOUT=\fINUM\fR .RS 4 NUM is the number of seconds to wait for \fBctdbd\fR(1) to shut down gracefully before giving up and killing it\&. .sp Defaults is 30\&. .RE .PP CTDB_STARTUP_TIMEOUT=\fINUM\fR .RS 4 NUM is the number of seconds to wait for \fBctdbd\fR(1) complete early initialisation up to a point where it is unlikely to abort\&. If \fBctdbd\fR doesn\*(Aqt complete the "setup" event before this timeout then it is killed\&. .sp Defaults is 10\&. .RE .SH "NETWORK CONFIGURATION" .SS "NAT GATEWAY" .PP NAT gateway is used to configure fallback routing for nodes when they do not host any public IP addresses\&. For example, it allows unhealthy nodes to reliably communicate with external infrastructure\&. One node in a NAT gateway group will be designated as the NAT gateway master node and other (slave) nodes will be configured with fallback routes via the NAT gateway master node\&. For more information, see the NAT GATEWAY section in \fBctdb\fR(7)\&. .PP CTDB_NATGW_DEFAULT_GATEWAY=\fIIPADDR\fR .RS 4 IPADDR is an alternate network gateway to use on the NAT gateway master node\&. A fallback default route is added via this network gateway\&. .sp No default\&. .RE .PP CTDB_NATGW_NODES=\fIFILENAME\fR .RS 4 FILENAME contains the list of nodes that belong to the same NAT gateway group\&. .sp File format: .sp .if n \{\ .RS 4 .\} .nf \fIIPADDR\fR .fi .if n \{\ .RE .\} .sp No default, usually /etc/ctdb/natgw_nodes when enabled\&. .RE .PP CTDB_NATGW_PRIVATE_NETWORK=\fIIPADDR/MASK\fR .RS 4 IPADDR/MASK is the private sub\-network that is internally routed via the NAT gateway master node\&. This is usually the private network that is used for node addresses\&. .sp No default\&. .RE .PP CTDB_NATGW_PUBLIC_IFACE=\fIIFACE\fR .RS 4 IFACE is the network interface on which the CTDB_NATGW_PUBLIC_IP will be configured\&. .sp No default\&. .RE .PP CTDB_NATGW_PUBLIC_IP=\fIIPADDR/MASK\fR .RS 4 IPADDR/MASK indicates the IP address that is used for outgoing traffic (originating from CTDB_NATGW_PRIVATE_NETWORK) on the NAT gateway master node\&. This \fImust not\fR be a configured public IP address\&. .sp No default\&. .RE .PP CTDB_NATGW_SLAVE_ONLY=yes|no .RS 4 When set to "yes" a node can not be a NAT gateway master node\&. .sp Default is no\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes CTDB_NATGW_PRIVATE_NETWORK=192\&.168\&.1\&.0/24 CTDB_NATGW_DEFAULT_GATEWAY=10\&.0\&.0\&.1 CTDB_NATGW_PUBLIC_IP=10\&.0\&.0\&.227/24 CTDB_NATGW_PUBLIC_IFACE=eth0 .fi .if n \{\ .RE .\} .RE .SS "POLICY ROUTING" .PP A node running CTDB may be a component of a complex network topology\&. In particular, public addresses may be spread across several different networks (or VLANs) and it may not be possible to route packets from these public addresses via the system\*(Aqs default route\&. Therefore, CTDB has support for policy routing via the 13\&.per_ip_routing eventscript\&. This allows routing to be specified for packets sourced from each public address\&. The routes are added and removed as CTDB moves public addresses between nodes\&. .PP For more information, see the POLICY ROUTING section in \fBctdb\fR(7)\&. .PP CTDB_PER_IP_ROUTING_CONF=\fIFILENAME\fR .RS 4 FILENAME contains elements for constructing the desired routes for each source address\&. .sp The special FILENAME value \fB__auto_link_local__\fR indicates that no configuration file is provided and that CTDB should generate reasonable link\-local routes for each public IP address\&. .sp File format: .sp .if n \{\ .RS 4 .\} .nf \fIIPADDR\fR \fIDEST\-IPADDR/MASK\fR [\fIGATEWAY\-IPADDR\fR] .fi .if n \{\ .RE .\} .sp No default, usually /etc/ctdb/policy_routing when enabled\&. .RE .PP CTDB_PER_IP_ROUTING_RULE_PREF=\fINUM\fR .RS 4 NUM sets the priority (or preference) for the routing rules that are added by CTDB\&. .sp This should be (strictly) greater than 0 and (strictly) less than 32766\&. A priority of 100 is recommended, unless this conflicts with a priority already in use on the system\&. See \fBip\fR(8), for more details\&. .RE .PP CTDB_PER_IP_ROUTING_TABLE_ID_LOW=\fILOW\-NUM\fR, CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=\fIHIGH\-NUM\fR .RS 4 CTDB determines a unique routing table number to use for the routing related to each public address\&. LOW\-NUM and HIGH\-NUM indicate the minimum and maximum routing table numbers that are used\&. .sp \fBip\fR(8) uses some reserved routing table numbers below 255\&. Therefore, CTDB_PER_IP_ROUTING_TABLE_ID_LOW should be (strictly) greater than 255\&. .sp CTDB uses the standard file /etc/iproute2/rt_tables to maintain a mapping between the routing table numbers and labels\&. The label for a public address \fIADDR\fR will look like ctdb\&.\fIaddr\fR\&. This means that the associated rules and routes are easy to read (and manipulate)\&. .sp No default, usually 1000 and 9000\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf CTDB_PER_IP_ROUTING_CONF=/etc/ctdb/policy_routing CTDB_PER_IP_ROUTING_RULE_PREF=100 CTDB_PER_IP_ROUTING_TABLE_ID_LOW=1000 CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=9000 .fi .if n \{\ .RE .\} .RE .SS "MISCELLANEOUS NETWORK CONFIGURATION" .PP CTDB_PARTIALLY_ONLINE_INTERFACES=yes|no .RS 4 Whether one or more offline interfaces should cause a monitor event to fail if there are other interfaces that are up\&. If this is "yes" and a node has some interfaces that are down then \fBctdb status\fR will display the node as "PARTIALLYONLINE"\&. .sp Default is "no"\&. .RE .SH "SERVICE CONFIGURATION" .PP CTDB can be configured to manage and/or monitor various NAS (and other) services via its eventscripts\&. .PP In the simplest case CTDB will manage a service\&. This means the service will be started and stopped along with CTDB, CTDB will monitor the service and CTDB will do any required reconfiguration of the service when public IP addresses are failed over\&. .SS "SAMBA" .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBEventscripts\fR .RS 4 .RS 4 49\&.winbind .RE .RS 4 50\&.samba .RE .RE .PP CTDB_MANAGES_SAMBA=yes|no .RS 4 Should CTDB manage Samba? .sp Default is no\&. .RE .PP CTDB_MANAGES_WINBIND=yes|no .RS 4 Should CTDB manage Winbind? .sp Default is no\&. .RE .PP CTDB_SAMBA_CHECK_PORTS=\fIPORT\-LIST\fR .RS 4 When monitoring Samba, check TCP ports in space\-separated PORT\-LIST\&. .sp Default is to monitor ports that Samba is configured to listen on\&. .RE .PP CTDB_SAMBA_SKIP_SHARE_CHECK=yes|no .RS 4 As part of monitoring, should CTDB skip the check for the existence of each directory configured as share in Samba\&. This may be desirable if there is a large number of shares\&. .sp Default is no\&. .RE .PP CTDB_SERVICE_NMB=\fISERVICE\fR .RS 4 Distribution specific SERVICE for managing nmbd\&. .sp Default is distribution\-dependant\&. .RE .PP CTDB_SERVICE_SMB=\fISERVICE\fR .RS 4 Distribution specific SERVICE for managing smbd\&. .sp Default is distribution\-dependant\&. .RE .PP CTDB_SERVICE_WINBIND=\fISERVICE\fR .RS 4 Distribution specific SERVICE for managing winbindd\&. .sp Default is "winbind"\&. .RE .SS "NFS" .PP This includes parameters for the kernel NFS server and the user\-space \m[blue]\fBNFS\-Ganesha\fR\m[]\&\s-2\u[1]\d\s+2 server\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBEventscripts\fR .RS 4 .RS 4 60\&.nfs .RE .RS 4 60\&.ganesha .RE .RE .PP CTDB_CLUSTER_FILESYSTEM_TYPE=gpfs .RS 4 The type of cluster filesystem to use with NFS\-ganesha\&. Currently only "gpfs" is supported\&. .sp Default is "gpfs"\&. .RE .PP CTDB_MANAGES_NFS=yes|no .RS 4 Should CTDB manage NFS? .sp Default is no\&. .RE .PP CTDB_MONITOR_NFS_THREAD_COUNT=yes|no .RS 4 Whether to monitor the NFS kernel server thread count\&. .sp This works around a limitation in some NFS initscripts where some threads can be stuck in host filesystem calls (perhaps due to slow storage), a restart occurs, some threads don\*(Aqt exit, the start only adds the missing number of threads, the stuck threads exit, and the result is a lower than expected thread count\&. Note that if you must also set \fIRPCNFSDCOUNT\fR (RedHat/Debian) or \fIUSE_KERNEL_NFSD_NUMBER\fR (SUSE) in your NFS configuration so the monitoring code knows how many threads there should be \- if neither of these are set then this option will be ignored\&. .sp Default is no\&. .RE .PP CTDB_NFS_DUMP_STUCK_THREADS=\fINUM\fR .RS 4 NUM is the number of NFS kernel server threads to dump stack traces for if some are still alive after stopping NFS during a restart\&. .sp Default is 0\&. .RE .PP CTDB_NFS_SERVER_MODE=kernel|ganesha .RS 4 Selects which NFS server to be managed\&. .sp This replaces the deprecated variable \fINFS_SERVER_MODE\fR\&. .sp Default is "kernel"\&. .RE .PP CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK=yes|no .RS 4 During monitoring, should CTDB skip the \fBrpcinfo\fR check that is used to see if the NFS kernel server is functional\&. .sp Default is no\&. .RE .PP CTDB_NFS_SKIP_SHARE_CHECK=yes|no .RS 4 As part of monitoring, should CTDB skip the check for the existence of each directory exported via NFS\&. This may be desirable if there is a large number of exports\&. .sp Default is no\&. .RE .PP CTDB_RPCINFO_LOCALHOST=\fIIPADDR\fR|\fIHOSTNAME\fR .RS 4 IPADDR or HOSTNAME indicates the address that \fBrpcinfo\fR should connect to when doing \fBrpcinfo\fR check on RPC service during monitoring\&. Optimally this would be "localhost"\&. However, this can add some performance overheads\&. .sp Default is "127\&.0\&.0\&.1"\&. .RE .PP CTDB_SKIP_GANESHA_NFSD_CHECK=yes|no .RS 4 As part of monitoring, should CTDB skip the check for the existence of each directory exported via NFS\-Ganesha\&. This may be desirable if there is a large number of exports\&. .sp Default is no\&. .RE .SS "APACHE HTTPD" .PP CTDB can manage the Apache web server\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBEventscript\fR .RS 4 .RS 4 41\&.httpd .RE .RE .PP CTDB_MANAGES_HTTPD=yes|no .RS 4 Should CTDB manage the Apache web server? .sp Default is no\&. .RE .SS "CLAMAV" .PP CTDB has support to manage the popular anti\-virus daemon ClamAV\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBEventscript\fR .RS 4 .RS 4 31\&.clamd .RE .PP This eventscript is not enabled by default\&. Use \fBctdb enablescript\fR to enable it\&. .RE .PP CTDB_MANAGES_CLAMD=yes|no .RS 4 Should CTDB manage ClamAV? .sp Default is no\&. .RE .PP CTDB_CLAMD_SOCKET=\fIFILENAME\fR .RS 4 FILENAME is the socket to monitor ClamAV\&. .sp No default\&. .RE .SS "ISCSI" .PP CTDB has support for managing the Linux iSCSI tgtd service\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBEventscript\fR .RS 4 .RS 4 70\&.iscsi .RE .RE .PP CTDB_MANAGES_ISCSI=yes|no .RS 4 Should CTDB manage iSCSI tgtd? .sp Default is no\&. .RE .PP CTDB_START_ISCSI_SCRIPTS=\fIDIRECTORY\fR .RS 4 DIRECTORY on shared storage containing scripts to start tgtd for each public IP address\&. .sp No default\&. .RE .SS "MULTIPATHD" .PP CTDB can monitor multipath devices to ensure that active paths are available\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBEventscript\fR .RS 4 .RS 4 20\&.multipathd .RE .PP This eventscript is not enabled by default\&. Use \fBctdb enablescript\fR to enable it\&. .RE .PP CTDB_MONITOR_MPDEVICES=\fIMP\-DEVICE\-LIST\fR .RS 4 MP\-DEVICE\-LIST is a list of multipath devices for CTDB to monitor? .sp No default\&. .RE .SS "VSFTPD" .PP CTDB can manage the vsftpd FTP server\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBEventscript\fR .RS 4 .RS 4 40\&.vsftpd .RE .RE .PP CTDB_MANAGES_VSFTPD=yes|no .RS 4 Should CTDB manage the vsftpd FTP server? .sp Default is no\&. .RE .SS "SYSTEM RESOURCE MONITORING CONFIGURATION" .PP CTDB can experience seemingly random (performance and other) issues if system resources become too contrained\&. Options in this section can be enabled to allow certain system resources to be checked\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBEventscripts\fR .RS 4 .RS 4 00\&.ctdb .RE .RS 4 40\&.fs_use .RE .PP Filesystem usage monitoring is in 40\&.fs_use\&. This eventscript is not enabled by default\&. Use \fBctdb enablescript\fR to enable it\&. .RE .PP CTDB_CHECK_FS_USE=\fIFS\-LIMIT\-LIST\fR .RS 4 FS\-LIMIT\-LIST is a space\-separated list of \fIFILESYSTEM\fR:\fILIMIT\fR pairs indicating that a node should be flagged unhealthy if the space used on FILESYSTEM reaches LIMIT%\&. .sp No default\&. .sp Note that this feature uses the 40\&.fs_use eventscript, which is not enabled by default\&. Use \fBctdb enablescript\fR to enable it\&. .RE .PP CTDB_CHECK_SWAP_IS_NOT_USED=yes|no .RS 4 Should a warning be logged if swap space is in use\&. .sp Default is no\&. .RE .PP CTDB_MONITOR_FREE_MEMORY=\fINUM\fR .RS 4 NUM is a lower limit on available system memory, expressed in megabytes\&. If this is set and the amount of available memory falls below this limit then some debug information will be logged, the node will be disabled and then CTDB will be shut down\&. .sp No default\&. .RE .PP CTDB_MONITOR_FREE_MEMORY_WARN=\fINUM\fR .RS 4 NUM is a lower limit on available system memory, expressed in megabytes\&. If this is set and the amount of available memory falls below this limit then a warning will be logged\&. .sp No default\&. .RE .SS "MISCELLANEOUS SERVICE\-RELATED CONFIGURATION" .PP CTDB_MANAGED_SERVICES=\fISERVICE\-LIST\fR .RS 4 SERVICE\-LIST is a space\-separated list of SERVICEs that CTDB should manage\&. This can be used as an alternative to the \fICTDB_MANAGES_\fR\fI\fISERVICE\fR\fR variables\&. .sp No default\&. .RE .PP CTDB_SERVICE_AUTOSTARTSTOP=yes|no .RS 4 When CTDB should start and stop services if they become managed or unmanaged\&. .sp Default is no\&. .RE .SH "TUNABLES CONFIGURATION" .PP CTDB tunables (see \fBctdbd-tunables\fR(7)) can be set from the configuration file\&. They are set as follows: .sp .if n \{\ .RS 4 .\} .nf CTDB_SET_\fITUNABLE\fR=\fIVALUE\fR .fi .if n \{\ .RE .\} .PP For example: .sp .if n \{\ .RS 4 .\} .nf CTDB_SET_MonitorInterval=20 .fi .if n \{\ .RE .\} .sp .SH "DEBUG AND TEST" .PP Variable in this section are for debugging and testing CTDB\&. They should not generally be needed\&. .PP CTDB_DEBUG_HUNG_SCRIPT=\fIFILENAME\fR .RS 4 FILENAME is a script to run to log debug information when an event script times out\&. .sp Default is \fICTDB_BASE\fR/debug\-hung\-script\&.sh\&. .RE .PP CTDB_DEBUG_LOCKS=\fIFILENAME\fR .RS 4 FILENAME is a script to run to log debug information when an CTDB fails to freeze databases during recovery\&. .sp No default, usually \fICTDB_BASE\fR/debug_locks\&.sh\&. .RE .PP CTDB_ETCDIR=\fIDIRECTORY\fR .RS 4 DIRECTORY containing system configuration files\&. This is used to provide alternate configuration when testing and should not need to be changed from the default\&. .sp Default is /etc\&. .RE .PP CTDB_INIT_STYLE=debian|redhat|suse .RS 4 This is the init style used by the Linux distribution (or other operating system) being used\&. This is usually determined dynamically by checking the system\&. This variable is used by the initscript to determine which init system primitives to use\&. It is also used by some eventscripts to choose the name of initscripts for certain services, since these can vary between distributions\&. .sp No fixed default\&. .sp If this option needs to be changed from the calculated default for the initscript to function properly, then it must be set in the distribution\-specific initscript configuration, such as /etc/sysconfig/ctdb .RE .PP CTDB_MAX_CORRUPT_DB_BACKUPS=\fINUM\fR .RS 4 NUM is the maximum number of volatile TDB database backups to be kept (for each database) when a corrupt database is found during startup\&. Volatile TDBs are zeroed during startup so backups are needed to debug any corruption that occurs before a restart\&. .sp Default is 10\&. .RE .PP CTDB_RC_LOCAL=\fIFILENAME\fR .RS 4 FILENAME is a script fragment to be sourced by the functions that is sourced by scripts\&. On example use would be to override function definitions in unit tests\&. As a sanity check, this file must be executable for it to be used\&. .sp No default\&. .RE .PP CTDB_RUN_TIMEOUT_MONITOR=yes|no .RS 4 Whether CTDB should simulate timing out monitor events\&. This uses the 99\&.timeout eventscript\&. .sp Default is no\&. .RE .PP CTDB_SCRIPT_DEBUGLEVEL=\fINUM\fR .RS 4 NUM is the level debugging messages printed by CTDB scripts\&. Setting this to a higher number (e\&.g\&. 4) will cause some scripts to log more messages\&. .sp Default is 2\&. .RE .PP CTDB_SUPPRESS_COREFILE=yes|no .RS 4 Whether CTDB core files should be suppressed\&. .sp Default is no\&. .RE .PP CTDB_VALGRIND=yes|no|\fICOMMAND\fR .RS 4 If "yes", this causes \fBctdbd\fR(1) to be run under \fBvalgrind\fR(1) with logs going to /var/log/ctdb_valgrind\&. If neither "yes" nor "no" then the value is assumed to be a COMMAND (e\&.g\&. a \fBvalgrind\fR variation, a \fBgdb\fR(1) command) that is used in place of the default \fBvalgrind\fR command\&. In either case, the \fB\-\-valgrind\fR option is passed to \fBctdbd\fR\&. .sp Default is no\&. .RE .SH "FILES" .RS 4 /etc/ctdb/ctdbd\&.conf .RE .RS 4 /etc/sysconfig/ctdb .RE .RS 4 /etc/default/ctdb .RE .RS 4 /etc/ctdb/sysconfig/ctdb .RE .SH "SEE ALSO" .PP \fBctdbd\fR(1), \fBctdbd_wrapper\fR(1), \fBonnode\fR(1), \fBctdb\fR(7), \fBctdb-tunables\fR(7), \m[blue]\fB\%http://ctdb.samba.org/\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Amitay Isaacs, Martin Schwenke .SH "COPYRIGHT" .br Copyright \(co 2007 Andrew Tridgell, Ronnie Sahlberg .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp .SH "NOTES" .IP " 1." 4 NFS-Ganesha .RS 4 \%https://github.com/nfs-ganesha/nfs-ganesha/wiki .RE ctdb-2.5.1.dfsg/doc/ctdbd.1.html0000644000175000017500000003603012245332460016104 0ustar mathieumathieuctdbd

Name

ctdbd — The CTDB cluster daemon

Synopsis

ctdbd [OPTION...]

DESCRIPTION

ctdbd is the main CTDB daemon.

Note that ctdbd is not usually invoked directly. It is invoked via ctdbd_wrapper(1) or via the initscript.

See ctdb(7) for an overview of CTDB.

GENERAL OPTIONS

-d, --debug=DEBUGLEVEL

This option sets the debug level to DEBUGLEVEL, which controls what will be written to the logfile. The default is 0 which will only log important events and errors. A larger number will provide additional logging.

See the DEBUG LEVELS section in ctdb(7) for more information.

--dbdir=DIRECTORY

DIRECTORY on local storage where ctdbd keeps a local copy of TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem.

This directory would usually be /var/ctdb

--dbdir-persistent=DIRECTORY

DIRECTORY on local storage where ctdbd keeps a local copy of persistent TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem.

This directory would usually be /etc/ctdb/persistent

--dbdir-state=DIRECTORY

DIRECTORY on local storage where ctdbd keep internal state TDB files. This directory is local for each node and should not be stored on the shared cluster filesystem.

This directory would usually be /var/ctdb/state

--event-script-dir=DIRECTORY

DIRECTORY where the CTDB event scripts are stored. See the EVENT SCRIPTS section in ctdb(7) for more information.

Default is CTDB_BASE/events.d, so usually /etc/ctdb/events.d, which is part of the CTDB installation.

--logfile=FILENAME

FILENAME where ctdbd will write its log. This is usually /var/log/log.ctdb.

--log-ringbuf-size=NUM

Set the size of the log ringbuffer to NUM entries.

CTDB uses an in-memory ringbuffer containing NUM most recent log entries for all log levels (except DEBUG). The ringbugger can be useful for extracting detailed logs even if some entries are not logged to the regular logs.

Use the ctdb getlog command to retrieve log entries from the ringbuffer.

--lvs

This option is used to activate the LVS capability on a CTDB node. Please see the LVS section in ctdb(7) for more information.

--max-persistent-check-errors=NUM

NUM specifies the maximum number of health check failures allowed for persistent databases during startup.

The default value is 0. Setting this to non-zero allows a node with unhealthy persistent databases to startup and join the cluster as long as there is another node with healthy persistent databases.

--nlist=FILENAME

FILENAME containing a list of the private IP addresses, one per line, for each node in the cluster. This file must be the same on each node in the cluster.

Default is CTDB_BASE/nodes, so usually /etc/ctdb/nodes.

--no-lmaster

This argument specifies that this node can NOT become an lmaster for records in the database. This means that it will never show up in the vnnmap. This feature is primarily used for making a cluster span across a WAN link and use CTDB as a WAN-accelerator.

Please see the REMOTE CLUSTER NODES section in ctdb(7) for more information.

--no-recmaster

This argument specifies that this node can NOT become a recmaster for the database. This feature is primarily used for making a cluster span across a WAN link and use CTDB as a WAN-accelerator.

Please see the REMOTE CLUSTER NODES section in ctdb(7) for more information.

--notification-script=FILENAME

FILENAME specifying a script to be invoked by ctdbd when certain state changes occur.

This file is usually /etc/ctdb/notify.sh.

Please see the NOTIFICATION SCRIPT section in ctdb(7) for more information.

--pidfile=FILENAME

FILENAME for file containing process ID of main CTDB daemon. This file is automatically created and removed by CTDB.

The default is to not create a PID file.

--public_addresses=FILENAME

FILENAME specifying a file containing the public IP addresses to use on the cluster when CTDB should use IP takeover. This file contains a list of IP addresses, netmasks and interfaces. CTDB will distribute these public IP addresses appropriately across the available nodes.

The IP addresses specified in this file can differ across nodes.

This is usually the file /etc/ctdb/public_addresses

--public-interface=INTERFACE

INTERFACE on which to attach public IP addresses or on which to attach the single-public-ip when used.

When using public IP addresses, this is only required if interfaces are not explicitly specified in the public addresses file.

--reclock=FILENAME

FILENAME is the name of the recovery lock file stored in shared storage that ctdbd uses to prevent split brains from occuring.

It is possible to run CTDB without a recovery lock file, but then there will be no protection against split brain if the cluster/network becomes partitioned. Using CTDB without a reclock file is strongly discouraged.

--single-public-ip=IPADDR

IPADDR specifies the single IP that CTDB will use in conjuction with LVS.

Please see the LVS section in ctdb(7) for more information.

--start-as-disabled

This makes ctdbd start in the DISABLED state.

To allow the node to host public IP addresses and services, it must be manually enabled using the ctdb enable command.

Please see the NODE STATES section in ctdb(7) for more information about the DISABLED state.

--start-as-stopped

This makes ctdbd start in the STOPPED state.

To allow the node to take part in the cluster it must be manually continued with the the ctdb enable command.

Please see the NODE STATES section in ctdb(7) for more information about the STOPPED state.

--syslog

Send log messages to syslog instead of the CTDB logfile. This option overrides --logfile. The default is to log to a file.

--transport=tcp|infiniband

This option specifies which transport to use for ctdbd internode communications. The default is "tcp".

The "infiniband" support is not regularly tested.

-?, --help

Display a summary of options.

DEBUGGING OPTIONS

-i, --interactive

Enable interactive mode. This will make ctdbd run in the foreground and not detach from the terminal. By default ctdbd will detach itself and run in the background as a daemon.

--listen=IPADDR

This specifies which IP address that ctdbd will bind to.

By default ctdbd will bind to the first address it finds in the /etc/ctdb/nodes file that is also present on the local system.

This option is only required when you want to run multiple ctdbd daemons/nodes on the same physical host in which case there would be multiple entries in /etc/ctdb/nodes that would match a local interface.

--nopublicipcheck

This option is used when testing with multiple local daemons on a single machine. It disables checks related to public IP addresses.

--nosetsched

This is a debugging option. This option is only used when debugging ctdbd.

Normally ctdbd will change its scheduler to run as a real-time process. This is the default mode for a normal ctdbd operation to gurarantee that ctdbd always gets the CPU cycles that it needs.

This option is used to tell ctdbd to not run as a real-time process and instead run ctdbd as a normal userspace process. This is useful for debugging and when you want to run ctdbd under valgrind or gdb. (You don't want to attach valgrind or gdb to a real-time process.)

--socket=FILENAME

FILENAME specifies the name of the Unix domain socket that ctdbd will create. This socket is used by local clients to communicate with ctdbd.

The default is /tmp/ctdb.socket . You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host, usually for testing.

--script-log-level=DEBUGLEVEL

This option sets the debug level of event script output to DEBUGLEVEL. The default is ERR (0).

See the DEBUG LEVELS section in ctdb(7) for more information.

--sloppy-start

This is debugging option. This speeds up the initial recovery during startup at the expense of some consistency checking. Don't use this option in production.

--torture

This option is only used for development and testing of CTDB. It adds artificial errors and failures to the common codepaths in ctdbd to verify that ctdbd can recover correctly from failures.

Do not use this option unless you are developing and testing new functionality in CTDB.

--valgrinding

This is a debugging option. This option is only used when debugging ctdbd. This enables additional debugging capabilities and implies --nosetsched.

SEE ALSO

ctdb(1), ctdbd_wrapper(1), onnode(1), ctdb(7), ctdb-tunables(7), http://ctdb.samba.org/

ctdb-2.5.1.dfsg/doc/ctdbd.10000644000175000017500000002666612245332457015165 0ustar mathieumathieu'\" t .\" Title: ctdbd .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "CTDBD" "1" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ctdbd \- The CTDB cluster daemon .SH "SYNOPSIS" .HP \w'\fBctdbd\fR\ 'u \fBctdbd\fR [\fIOPTION\fR...] .SH "DESCRIPTION" .PP ctdbd is the main CTDB daemon\&. .PP Note that ctdbd is not usually invoked directly\&. It is invoked via \fBctdbd_wrapper\fR(1) or via the initscript\&. .PP See \fBctdb\fR(7) for an overview of CTDB\&. .SH "GENERAL OPTIONS" .PP \-d, \-\-debug=\fIDEBUGLEVEL\fR .RS 4 This option sets the debug level to DEBUGLEVEL, which controls what will be written to the logfile\&. The default is 0 which will only log important events and errors\&. A larger number will provide additional logging\&. .sp See the DEBUG LEVELS section in \fBctdb\fR(7) for more information\&. .RE .PP \-\-dbdir=\fIDIRECTORY\fR .RS 4 DIRECTORY on local storage where ctdbd keeps a local copy of TDB databases\&. This directory is local for each node and should not be stored on the shared cluster filesystem\&. .sp This directory would usually be /var/ctdb .RE .PP \-\-dbdir\-persistent=\fIDIRECTORY\fR .RS 4 DIRECTORY on local storage where ctdbd keeps a local copy of persistent TDB databases\&. This directory is local for each node and should not be stored on the shared cluster filesystem\&. .sp This directory would usually be /etc/ctdb/persistent .RE .PP \-\-dbdir\-state=\fIDIRECTORY\fR .RS 4 DIRECTORY on local storage where ctdbd keep internal state TDB files\&. This directory is local for each node and should not be stored on the shared cluster filesystem\&. .sp This directory would usually be /var/ctdb/state .RE .PP \-\-event\-script\-dir=\fIDIRECTORY\fR .RS 4 DIRECTORY where the CTDB event scripts are stored\&. See the EVENT SCRIPTS section in \fBctdb\fR(7) for more information\&. .sp Default is \fBCTDB_BASE\fR/events\&.d, so usually /etc/ctdb/events\&.d, which is part of the CTDB installation\&. .RE .PP \-\-logfile=\fIFILENAME\fR .RS 4 FILENAME where ctdbd will write its log\&. This is usually /var/log/log\&.ctdb\&. .RE .PP \-\-log\-ringbuf\-size=\fINUM\fR .RS 4 Set the size of the log ringbuffer to NUM entries\&. .sp CTDB uses an in\-memory ringbuffer containing NUM most recent log entries for all log levels (except DEBUG)\&. The ringbugger can be useful for extracting detailed logs even if some entries are not logged to the regular logs\&. .sp Use the \fBctdb getlog\fR command to retrieve log entries from the ringbuffer\&. .RE .PP \-\-lvs .RS 4 This option is used to activate the LVS capability on a CTDB node\&. Please see the LVS section in \fBctdb\fR(7) for more information\&. .RE .PP \-\-max\-persistent\-check\-errors=\fINUM\fR .RS 4 NUM specifies the maximum number of health check failures allowed for persistent databases during startup\&. .sp The default value is 0\&. Setting this to non\-zero allows a node with unhealthy persistent databases to startup and join the cluster as long as there is another node with healthy persistent databases\&. .RE .PP \-\-nlist=\fIFILENAME\fR .RS 4 FILENAME containing a list of the private IP addresses, one per line, for each node in the cluster\&. This file \fImust be the same on each node\fR in the cluster\&. .sp Default is \fBCTDB_BASE\fR/nodes, so usually /etc/ctdb/nodes\&. .RE .PP \-\-no\-lmaster .RS 4 This argument specifies that this node can NOT become an lmaster for records in the database\&. This means that it will never show up in the vnnmap\&. This feature is primarily used for making a cluster span across a WAN link and use CTDB as a WAN\-accelerator\&. .sp Please see the REMOTE CLUSTER NODES section in \fBctdb\fR(7) for more information\&. .RE .PP \-\-no\-recmaster .RS 4 This argument specifies that this node can NOT become a recmaster for the database\&. This feature is primarily used for making a cluster span across a WAN link and use CTDB as a WAN\-accelerator\&. .sp Please see the REMOTE CLUSTER NODES section in \fBctdb\fR(7) for more information\&. .RE .PP \-\-notification\-script=\fIFILENAME\fR .RS 4 FILENAME specifying a script to be invoked by ctdbd when certain state changes occur\&. .sp This file is usually /etc/ctdb/notify\&.sh\&. .sp Please see the NOTIFICATION SCRIPT section in \fBctdb\fR(7) for more information\&. .RE .PP \-\-pidfile=\fIFILENAME\fR .RS 4 FILENAME for file containing process ID of main CTDB daemon\&. This file is automatically created and removed by CTDB\&. .sp The default is to not create a PID file\&. .RE .PP \-\-public_addresses=\fIFILENAME\fR .RS 4 FILENAME specifying a file containing the public IP addresses to use on the cluster when CTDB should use IP takeover\&. This file contains a list of IP addresses, netmasks and interfaces\&. CTDB will distribute these public IP addresses appropriately across the available nodes\&. .sp The IP addresses specified in this file can differ across nodes\&. .sp This is usually the file /etc/ctdb/public_addresses .RE .PP \-\-public\-interface=\fIINTERFACE\fR .RS 4 INTERFACE on which to attach public IP addresses or on which to attach the single\-public\-ip when used\&. .sp When using public IP addresses, this is only required if interfaces are not explicitly specified in the public addresses file\&. .RE .PP \-\-reclock=\fIFILENAME\fR .RS 4 FILENAME is the name of the recovery lock file stored in \fIshared storage\fR that ctdbd uses to prevent split brains from occuring\&. .sp It is possible to run CTDB without a recovery lock file, but then there will be no protection against split brain if the cluster/network becomes partitioned\&. Using CTDB without a reclock file is strongly discouraged\&. .RE .PP \-\-single\-public\-ip=\fIIPADDR\fR .RS 4 IPADDR specifies the single IP that CTDB will use in conjuction with LVS\&. .sp Please see the LVS section in \fBctdb\fR(7) for more information\&. .RE .PP \-\-start\-as\-disabled .RS 4 This makes ctdbd start in the DISABLED state\&. .sp To allow the node to host public IP addresses and services, it must be manually enabled using the \fBctdb enable\fR command\&. .sp Please see the NODE STATES section in \fBctdb\fR(7) for more information about the DISABLED state\&. .RE .PP \-\-start\-as\-stopped .RS 4 This makes ctdbd start in the STOPPED state\&. .sp To allow the node to take part in the cluster it must be manually continued with the the \fBctdb enable\fR command\&. .sp Please see the NODE STATES section in \fBctdb\fR(7) for more information about the STOPPED state\&. .RE .PP \-\-syslog .RS 4 Send log messages to syslog instead of the CTDB logfile\&. This option overrides \-\-logfile\&. The default is to log to a file\&. .RE .PP \-\-transport=tcp|infiniband .RS 4 This option specifies which transport to use for ctdbd internode communications\&. The default is "tcp"\&. .sp The "infiniband" support is not regularly tested\&. .RE .PP \-?, \-\-help .RS 4 Display a summary of options\&. .RE .SH "DEBUGGING OPTIONS" .PP \-i, \-\-interactive .RS 4 Enable interactive mode\&. This will make ctdbd run in the foreground and not detach from the terminal\&. By default ctdbd will detach itself and run in the background as a daemon\&. .RE .PP \-\-listen=\fIIPADDR\fR .RS 4 This specifies which IP address that ctdbd will bind to\&. .sp By default ctdbd will bind to the first address it finds in the /etc/ctdb/nodes file that is also present on the local system\&. .sp This option is only required when you want to run multiple ctdbd daemons/nodes on the same physical host in which case there would be multiple entries in /etc/ctdb/nodes that would match a local interface\&. .RE .PP \-\-nopublicipcheck .RS 4 This option is used when testing with multiple local daemons on a single machine\&. It disables checks related to public IP addresses\&. .RE .PP \-\-nosetsched .RS 4 This is a debugging option\&. This option is only used when debugging ctdbd\&. .sp Normally ctdbd will change its scheduler to run as a real\-time process\&. This is the default mode for a normal ctdbd operation to gurarantee that ctdbd always gets the CPU cycles that it needs\&. .sp This option is used to tell ctdbd to \fInot\fR run as a real\-time process and instead run ctdbd as a normal userspace process\&. This is useful for debugging and when you want to run ctdbd under valgrind or gdb\&. (You don\*(Aqt want to attach valgrind or gdb to a real\-time process\&.) .RE .PP \-\-socket=\fIFILENAME\fR .RS 4 FILENAME specifies the name of the Unix domain socket that ctdbd will create\&. This socket is used by local clients to communicate with ctdbd\&. .sp The default is /tmp/ctdb\&.socket \&. You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host, usually for testing\&. .RE .PP \-\-script\-log\-level=\fIDEBUGLEVEL\fR .RS 4 This option sets the debug level of event script output to DEBUGLEVEL\&. The default is ERR (0)\&. .sp See the DEBUG LEVELS section in \fBctdb\fR(7) for more information\&. .RE .PP \-\-sloppy\-start .RS 4 This is debugging option\&. This speeds up the initial recovery during startup at the expense of some consistency checking\&. \fIDon\*(Aqt use this option in production\fR\&. .RE .PP \-\-torture .RS 4 This option is only used for development and testing of CTDB\&. It adds artificial errors and failures to the common codepaths in ctdbd to verify that ctdbd can recover correctly from failures\&. .sp \fIDo not use this option\fR unless you are developing and testing new functionality in CTDB\&. .RE .PP \-\-valgrinding .RS 4 This is a debugging option\&. This option is only used when debugging ctdbd\&. This enables additional debugging capabilities and implies \-\-nosetsched\&. .RE .SH "SEE ALSO" .PP \fBctdb\fR(1), \fBctdbd_wrapper\fR(1), \fBonnode\fR(1), \fBctdb\fR(7), \fBctdb-tunables\fR(7), \m[blue]\fB\%http://ctdb.samba.org/\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Ronnie Sahlberg, Amitay Isaacs, Martin Schwenke .SH "COPYRIGHT" .br Copyright \(co 2007 Andrew Tridgell, Ronnie Sahlberg .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp ctdb-2.5.1.dfsg/doc/recovery-process.txt0000644000175000017500000005203012245023514020045 0ustar mathieumathieuValid as of 1.0.66, may/will change in the future RECMASTER ========= Recovery Master, this is one of the nodes in the cluster that has been designated to be the "recovery master". The recovery master is responsible for performing full checks of cluster and cluster node consistency and is also responsible for performing the actual database recovery procedure. Only one node at a time can be the recovery master. This is ensured by CTDB using a lock on a single file in the shared gpfs filesystem: /etc/sysconfig/ctdb : ... # Options to ctdbd. This is read by /etc/init.d/ctdb # you must specify the location of a shared lock file across all the # nodes. This must be on shared storage # there is no default here CTDB_RECOVERY_LOCK=/gpfs/.ctdb/shared ... In order to prevent that two nodes become recovery master at the same time (==split brain) CTDB here relies on GPFS that GPFS will guarantee coherent locking across the cluster. Thus CTDB relies on that GPFS MUST only allow one ctdb process on one node to take out and hold this lock. The recovery master is designated through an election process. VNNMAP ====== The VNNMAP is a list of all nodes in the cluster that is currently part of the cluster and participates in hosting the cluster databases. All nodes that are CONNECTED but not BANNED be present in the VNNMAP. The VNNMAP is the list of LMASTERS for the cluster as reported by 'ctdb status' " ... Size:3 hash:0 lmaster:0 hash:1 lmaster:1 hash:2 lmaster:2 ... CLUSTER MONITORING ================== All nodes in the cluster monitor its own health and its own consistency regards to the recovery master. How and what the nodes monitor for differs between the node which is the recovery master and normal nodes. This monitoring it to ensure that the cluster is healthy and consistent. This is not related to monitoring of inidividual node health, a.k.a. eventscript monitroing. At the end of each step in the process are listed some of the most common and important error messages that can be generated during that step. NORMAL NODE CLUSTER MONITORING ------------------------------ Monitoring is performed in the dedicated recovery daemon process. The implementation can be found in server/ctdb_recoverd.c:monitor_cluster() This is an overview of the more important tasks during monitoring. These tests are to verify that the local node is consistent with the recovery master. Once every second the following monitoring loop is performed : 1, Verify that the parent ctdb daemon on the local node is still running. If it is not, the recovery daemon logs an error and terminates. "CTDB daemon is no longer available. Shutting down recovery daemon" 2, Check if any of the nodes has been recorded to have misbehaved too many times. If so we ban the node and log a message : "Node %u has caused %u failures in %.0f seconds - banning it for %u seconds" 3, Check that there is a recovery master. If not we initiate a clusterwide election process and log : "Initial recovery master set - forcing election" and we restart monitoring from 1. 4, Verify that recovery daemon and the local ctdb daemon agreed on all the node BANNING flags. If the recovery daemon and the local ctdb daemon disagrees on these flags we update the local ctdb daemon, logs one of two messages and restarts monitoring from 1 again. "Local ctdb daemon on recmaster does not think this node is BANNED but the recovery master disagrees. Unbanning the node" "Local ctdb daemon on non-recmaster does not think this node is BANNED but the recovery master disagrees. Re-banning the node" 5, Verify that the node designated to be recovery master exists in the local list of all nodes. If the recovery master is not in the list of all cluster nodes a new recovery master election is triggered and monitoring restarts from 1. "Recmaster node %u not in list. Force reelection" 6, Check if the recovery master has become disconnected. If is has, log an error message, force a new election and restart monitoring from 1. "Recmaster node %u is disconnected. Force reelection" 7, Read the node flags off the recovery master and verify that it has not become banned. If is has, log an error message, force a new election and restart monitoring from 1. "Recmaster node %u no longer available. Force reelection" 8, Verify that the recmaster and the local node agrees on the flags (BANNED/DISABLED/...) for the local node. If there is an inconsistency, push the flags for the local node out to all other nodes. "Recmaster disagrees on our flags flags:0x%x recmaster_flags:0x%x Broadcasting out flags." 9, Verify that the local node hosts all public ip addresses it should host and that it does NOT host any public addresses it should not host. If there is an inconsistency we log an error, trigger a recovery to occur and restart monitoring from 1 again. "Public address '%s' is missing and we should serve this ip" "We are still serving a public address '%s' that we should not be serving." These are all the checks we perform during monitoring for a normal node. These tests are performed on all nodes in the cluster which is why it is optimized to perform as few network calls to other nodes as possible. Each node only performs 1 call to the recovery master in each loop and to no other nodes. RECOVERY MASTER CLUSTER MONITORING ----------------------------------- The recovery master performs a much more extensive test. In addition to tests 1-9 above the recovery master also performs the following tests: 10, Read the list of nodes and flags from all other CONNECTED nodes in the cluster. If there is a failure to read this list from one of the nodes, then log an error, mark this node as a candidate to become BANNED and restart monitoring from 1. "Unable to get nodemap from remote node %u" 11, Verify that the local recovery master and the remote node agrees on the flags for the remote node. If there is a inconsistency for the BANNING flag, log an error, trigger a new recmaster election and restart monitoring from 1. "Remote node %u had different BANNED flags 0x%x, local had 0x%x - trigger a re-election" "Remote node %u had flags 0x%x, local had 0x%x - updating local" 12, Verify that the local recovery master and the remote node agrees on the flags for the remote node. If one of the flags other than the BANNING flag was inconsistent, just update the set of flags for the local recovery daemon, log an information message and continue monitoring. "Remote node %u had flags 0x%x, local had 0x%x - updating local" 13, Read the list of public ip addresses from all of the CONNECTED nodes and merge into a single clusterwide list. If we fail to read the list of ips from a node, log an error and restart monitoring from 1. "Failed to read public ips from node : %u" 14, Verify that all other nodes agree that this node is the recovery master. If one of the other nodes discgrees this is the recovery master, log an error, force a new election and restart monitoring from 1. "Node %d does not agree we are the recmaster. Need a new recmaster election" 15, Check if the previous attempt to run a recovery failed, and if it did, try a new recovery. After the recovery, restart monitoring from 1. "Starting do_recovery" 16, Verify that all CONNECTED nodes in the cluster are in recovery mode NORMAL. If one of the nodes were in recovery mode ACTIVE, force a new recovery and restart monitoring from 1. "Node:%u was in recovery mode. Start recovery process" 17, Verify that the filehandle to the recovery lock file is valid. If it is not, this may mean a split brain and is a critical error. Try a new recovery and restart monitoring from 1. "recovery master doesn't have the recovery lock" 18, Verify that GPFS allows us to read from the recovery lock file. If not there is a critical GPFS issue and we may have a split brain. Try forcing a new recovery and restart monitoring from 1. "failed read from recovery_lock_fd - %s" 19, Read the list of all nodes and flags from all CONNECTED nodes in the cluster. If fail to read the nodemap from one of the remote nodes, log an error and restart monitoring from 1. "Unable to get nodemap from remote node %u" 20, If the nodemap differs between the local node and the remote node, log an error and force a recovery. This would happen if the /etc/ctdb/nodes file differs across nodes in the cluster. It is unlikely that the recovery will rectify the situation. This is a critical error, it is most likely the entire cluster will be unavailable until the files are fixed or have became banned. "Remote node:%u has different node count. %u vs %u of the local node" 21, If a remote node disagrees on the content of the nodes list, try a recovery and restart monitoring from 1. It is unlikely that the recovery will rectify the situation. This is a critical error, it is most likely the entire cluster will be unavailable until the files are fixed or have became banned. "Remote node:%u has different nodemap pnn for %d (%u vs %u)." 22, If a remote node disgrees on the node flags in the list, try a recovery to re-sync the flags and restart monitoring from 1. "Remote node:%u has different nodemap flag for %d (0x%x vs 0x%x)" 23, Verify that all active nodes are part of the VNNMAP. If not, this would be a new node that has become CONNECTED but does not yet participate in the cluster. Perform a recovery to merge the new node to the cluster and restart monitoring from 1. "The vnnmap count is different from the number of active nodes. %u vs %u" or "Node %u is active in the nodemap but did not exist in the vnnmap" 24, Read the VNNMAP from all CONNECTED nodes. Verify that all nodes have the same VNNMAP content and that all nodes are in the same generation instance of the databases. If not, force a recovery to re-synchronize the vnnmap and the databases across the cluster and restart monitoring from 1. "Remote node %u has different generation of vnnmap. %u vs %u (ours)" "Remote node %u has different size of vnnmap. %u vs %u (ours)" "Remote node %u has different vnnmap." 25, If there has been changes to the cluster that requires a reallocation of public ip addresses. On all nodes run the "startrecovery" event. Run "releaseip" and "takeip" events to reassign the ips across the cluster and finally run the "recovered" event. Finished monitoring, continue monitoring from 1. CLUSTER RECOVERY ================ Recoveries are driven by the recovery daemon on the node that is currently the recovery master. Most of the logging that is performed during recovery is only logged on the node that is the recovery master. Make sure to find which node is the recovery master and check the log for that node. Example log entries that start in column 1 are expected to be present in the log. Example log entries that are indented 3 columns are optional and might only be present if an error occured. 1, Log that recovery has been initiated. "Starting do_recovery" It might log an informational message : "New recovery culprit %u". This is only semi-accurate and might may not mean that there is any problem at all with the node indicated. 2, Check if a node has caused too many failed recoveries and if so ban it from the cluster, giving the other nodes in the cluster a chance to recovery operation. "Node %u has caused %u recoveries in %.0f seconds - banning it for %u seconds" 3, Verify that the recovery daemon can lock the recovery lock file. At this stage this should be recovery master. If this operation fails it means we have a split brain and have to abort recovery. "("ctdb_recovery_lock: Unable to open %s - (%s)" "ctdb_recovery_lock: Failed to get recovery lock on '%s'" "Unable to get recovery lock - aborting recovery" "ctdb_recovery_lock: Got recovery lock on '%s'" 4, Log which node caused the recovery to be initiated. This is a semi-accurate information message only. This line does NOT mean that there has to be something wrong with the node listed. "Recovery initiated due to problem with node %u" 5, Pull the names of all databases from all nodes and verify that these databases also exists locally. If a database is missing locally, just create it. It is not an error if a database is missing locally. Databases are created on demand and this could happen if it was one database which samba has never tried to access on the local node. 6, Check the list of databases on each remote node and create any databases that may be missing on the remote node. "Recovery - created remote databases" 7, Set recovery mode to ACTIVE on all remote nodes. 8, Run the "startrecovery" eventscript on all nodes. At this stage you will also get a few additional log entries, these are not from the recovery daemon but from the main ctdb daemon due to running the eventscript : "startrecovery eventscript has been invoked" "Monitoring has been disabled" "Executing event script ... ... 9, Create a new generation id and update the generation id and the VNNMAP on the local node only. This guarantees that the generation id will now be inconsistent across the cluster and that if recovery fails a new recovery is attempted in the next iteration of the monitoring loop. 10, Start a TDB TRANSACTION on all nodes for all databases. This is to ensure that if recovery is aborted or fails that we do not modify any databases on only some of the nodes. "started transactions on all nodes" 11, For each database, pull the content from all CONNECTED nodes and merge it into the TDB databases on the local node. This merges the records from the remote nodes based on their serial numbers so we only keep the most recent record found. "Recovery - pulled remote database 0x%x" 12, For each database, perform a fast TDB WIPE operation to delete the entire TDB under the transaction started above. 13, For each database, drop all empty records. Force the DMASTER field of all records to point to the recovery master. Push the database out to all other nodes. The PUSH process lists some additional log entries for each database of the form : "Recovery - pulled remote database 0x..." "Recovery - pushed remote database 0x... of size ..." 14, Commit all changes to all TDB databases. "Recovery - starting database commits" "Recovery - committed databases" 15, Create a new VNNMAP of all CONNECTED nodes, create a new generation number and piush this new VNNMAP out to all nodes. "Recovery - updated vnnmap" 16, Update all nodes that the local node is the recovery master. "Recovery - updated recmaster" 17, synchronize node flags across the cluster. "Recovery - updated flags" 18, Change recovery mode back to NORMAL. "Recovery - disabled recovery mode" 19, Re-allocate all public ip addresses across the cluster. "Deterministic IPs enabled. Resetting all ip allocations" If the IP address allocation on the local node changes you might get "Takeover of IP 10.0.0.201/24 on interface eth0" "Release of IP 10.0.0.204/24 on interface eth0" "Recovery - takeip finished" 20, Run the "recovered" eventscript on all nodes. "Recovery - finished the recovered event" You will also get an entry from the local ctdb daemon itself that it has switched back to recovery mode NORMAL. "Recovery has finished" 21, Broadcast a message to all samba daemons in the cluster that the databases have been recovered. Samba will now do some additional checking/cleanup of the content in the stored records. "Recovery complete" 22. Finished. At this stage a 10 second timeout (ctdb listvars : rerecoverytimeout) is initiated. The cluster will not allow a new recovery to be performed until this timeout has expired. "New recoveries supressed for the rerecovery timeout" "Rerecovery timeout elapsed. Recovery reactivated." Example : RECOVERY LOG ON RECMASTER ==================================== 2008/12/01 09:57:28.110732 [ 4933]: 10.0.0.21:4379: node 10.0.0.24:4379 is dead: 2 connected 2008/12/01 09:57:28.110838 [ 4933]: Tearing down connection to dead node :3 2008/12/01 09:57:28.967297 [ 4935]: server/ctdb_recoverd.c:2682 The vnnmap count is different from the number of active nodes. 4 vs 3 2008/12/01 09:57:28.967297 [ 4935]: server/ctdb_recoverd.c:1327 Starting do_recovery 2008/12/01 09:57:28.967297 [ 4935]: ctdb_recovery_lock: Got recovery lock on '/gpfs/.ctdb/shared' 2008/12/01 09:57:28.967297 [ 4935]: server/ctdb_recoverd.c:1355 Recovery initiated due to problem with node 0 2008/12/01 09:57:28.967297 [ 4935]: server/ctdb_recoverd.c:1381 Recovery - created remote databases 2008/12/01 09:57:28.973543 [ 4933]: server/ctdb_recover.c:589 Recovery mode set to ACTIVE 2008/12/01 09:57:28.974823 [ 4933]: server/ctdb_recover.c:904 startrecovery eventscript has been invoked 2008/12/01 09:57:29.187264 [ 4935]: server/ctdb_recoverd.c:1431 started transactions on all nodes 2008/12/01 09:57:29.187264 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x42fe72c5 2008/12/01 09:57:29.187264 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x42fe72c5 of size 0 2008/12/01 09:57:29.187264 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x1421fb78 2008/12/01 09:57:29.197262 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x1421fb78 of size 0 2008/12/01 09:57:29.197262 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0xc0bdde6a 2008/12/01 09:57:29.197262 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0xc0bdde6a of size 0 2008/12/01 09:57:29.197262 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x17055d90 2008/12/01 09:57:29.207261 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x17055d90 of size 8 2008/12/01 09:57:29.207261 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x7bbbd26c 2008/12/01 09:57:29.207261 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x7bbbd26c of size 1 2008/12/01 09:57:29.207261 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0xf2a58948 2008/12/01 09:57:29.217259 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0xf2a58948 of size 51 2008/12/01 09:57:29.217259 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x92380e87 2008/12/01 09:57:29.217259 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x92380e87 of size 17 2008/12/01 09:57:29.227258 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x63501287 2008/12/01 09:57:29.227258 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x63501287 of size 1 2008/12/01 09:57:29.227258 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0xe98e08b6 2008/12/01 09:57:29.227258 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0xe98e08b6 of size 4 2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0x2672a57f 2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0x2672a57f of size 28 2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1268 Recovery - pulled remote database 0xb775fff6 2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1230 Recovery - pushed remote database 0xb775fff6 of size 6 2008/12/01 09:57:29.237256 [ 4935]: server/ctdb_recoverd.c:1440 Recovery - starting database commits 2008/12/01 09:57:29.297247 [ 4935]: server/ctdb_recoverd.c:1452 Recovery - committed databases 2008/12/01 09:57:29.297247 [ 4935]: server/ctdb_recoverd.c:1502 Recovery - updated vnnmap 2008/12/01 09:57:29.297247 [ 4935]: server/ctdb_recoverd.c:1511 Recovery - updated recmaster 2008/12/01 09:57:29.297247 [ 4935]: server/ctdb_recoverd.c:1522 Recovery - updated flags 2008/12/01 09:57:29.305235 [ 4933]: server/ctdb_recover.c:589 Recovery mode set to NORMAL 2008/12/01 09:57:29.307245 [ 4935]: server/ctdb_recoverd.c:1531 Recovery - disabled recovery mode 2008/12/01 09:57:29.307245 [ 4935]: Deterministic IPs enabled. Resetting all ip allocations 2008/12/01 09:57:29.311071 [ 4933]: takeoverip called for an ip '10.0.0.201' that is not a public address 2008/12/01 09:57:29.311186 [ 4933]: takeoverip called for an ip '10.0.0.202' that is not a public address 2008/12/01 09:57:29.311204 [ 4933]: takeoverip called for an ip '10.0.0.203' that is not a public address 2008/12/01 09:57:29.311299 [ 4933]: takeoverip called for an ip '10.0.0.204' that is not a public address 2008/12/01 09:57:29.537210 [ 4935]: server/ctdb_recoverd.c:1542 Recovery - takeip finished 2008/12/01 09:57:29.545404 [ 4933]: Recovery has finished 2008/12/01 09:57:29.807169 [ 4935]: server/ctdb_recoverd.c:1551 Recovery - finished the recovered event 2008/12/01 09:57:29.807169 [ 4935]: server/ctdb_recoverd.c:1557 Recovery complete 2008/12/01 09:57:29.807169 [ 4935]: server/ctdb_recoverd.c:1565 New recoveries supressed for the rerecovery timeout 2008/12/01 09:57:39.815648 [ 4935]: server/ctdb_recoverd.c:1567 Rerecovery timeout elapsed. Recovery reactivated. ctdb-2.5.1.dfsg/doc/onnode.1.html0000644000175000017500000002022612245332461016307 0ustar mathieumathieuonnode

Name

onnode — run commands on CTDB cluster nodes

Synopsis

onnode [OPTION...] {NODES} {COMMAND}

DESCRIPTION

onnode is a utility to run commands on a specific node of a CTDB cluster, or on all nodes.

NODES specifies which node(s) to run a command on. See section NODES SPECIFICATION for details.

COMMAND can be any shell command. The onnode utility uses ssh or rsh to connect to the remote nodes and run the command.

OPTIONS

-c

Execute COMMAND in the current working directory on the specified nodes.

-f FILENAME

Specify an alternative nodes FILENAME to use instead of the default. This option overrides the CTDB_NODES_FILE environment variable. See the discussion of /etc/ctdb/nodes in the FILES section for more details.

-i

Keep standard input open, allowing data to be piped to onnode. Normally onnode closes stdin to avoid surprises when scripting. Note that this option is ignored when using -p or if SSH is set to anything other than "ssh".

-n

Allow nodes to be specified by name rather than node numbers. These nodes don't need to be listed in the nodes file. You can avoid the nodes file entirely by combining this with -f /dev/null.

-o PREFIX

Causes standard output from each node to be saved into a file with name PREFIX.IP.

-p

Run COMMAND in parallel on the specified nodes. The default is to run COMMAND sequentially on each node.

-P

Push files to nodes. Names of files to push are specified rather than the usual command. Quoting is fragile/broken - filenames with whitespace in them are not supported.

-q

Do not print node addresses. Normally, onnode prints informational node addresses if more than one node is specified. This overrides -v.

-v

Print node addresses even if only one node is specified. Normally, onnode prints informational node addresses when more than one node is specified.

-h, --help

Show a short usage guide.

NODES SPECIFICATION

Nodes can be specified via numeric node numbers (from 0 to N-1) or mnemonics. Multiple nodes are specified using lists of nodes, separated by commas, and ranges of numeric node numbers, separated by dashes. If nodes are specified multiple times then the command will be executed multiple times on those nodes. The order of nodes is significant.

The following mnemonics are available:

all

All nodes.

any

A node where ctdbd is running. This semi-random but there is a bias towards choosing a low numbered node.

ok | healthy

All nodes that are not disconnected, banned, disabled or unhealthy.

con | connected

All nodes that are not disconnected.

lvs | lvsmaster

The current LVS master.

natgw | natgwlist

The current NAT gateway.

rm | recmaster

The current recovery master.

EXAMPLES

The following command would show the process ID of ctdbd on all nodes

      onnode all ctdb getpid
    

The following command would show the last 5 lines of log on each node, preceded by the node's hostname

      onnode all "hostname; tail -5 /var/log/log.ctdb"
    

The following command would restart the ctdb service on all nodes, in parallel.

      onnode -p all service ctdb restart
    

The following command would run ./foo in the current working directory, in parallel, on nodes 0, 2, 3 and 4.

      onnode -c -p 0,2-4 ./foo
    

ENVIRONMENT

CTDB_BASE

Directory containing CTDB configuration files. The default is /etc/ctdb.

CTDB_NODES_FILE

Name of alternative nodes file to use instead of the default. See the FILES section for more details.

FILES

/etc/ctdb/nodes

Default file containing a list of each node's IP address or hostname.

Actually, the default is $CTDB_BASE/nodes, where CTDB_BASE defaults to /etc/ctdb. If a relative path is given (via the -f option or CTDB_BASE) and no corresponding file exists relative to the current directory then the file is also searched for in the $CTDB_BASE directory.

/etc/ctdb/onnode.conf

If this file exists it is sourced by onnode. The main purpose is to allow the administrator to set SSH to something other than "ssh". In this case the -t option is ignored. For example, the administrator may choose to use use rsh instead of ssh.

SEE ALSO

ctdb(7), http://ctdb.samba.org/

ctdb-2.5.1.dfsg/doc/ctdbd.1.xml0000644000175000017500000004313112245023514015735 0ustar mathieumathieu ctdbd 1 ctdb CTDB - clustered TDB database ctdbd The CTDB cluster daemon ctdbd OPTION DESCRIPTION ctdbd is the main CTDB daemon. Note that ctdbd is not usually invoked directly. It is invoked via ctdbd_wrapper 1 or via the initscript. See ctdb 7 for an overview of CTDB. GENERAL OPTIONS -d, --debug=DEBUGLEVEL This option sets the debug level to DEBUGLEVEL, which controls what will be written to the logfile. The default is 0 which will only log important events and errors. A larger number will provide additional logging. See the DEBUG LEVELS section in ctdb 7 for more information. --dbdir=DIRECTORY DIRECTORY on local storage where ctdbd keeps a local copy of TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem. This directory would usually be /var/ctdb --dbdir-persistent=DIRECTORY DIRECTORY on local storage where ctdbd keeps a local copy of persistent TDB databases. This directory is local for each node and should not be stored on the shared cluster filesystem. This directory would usually be /etc/ctdb/persistent --dbdir-state=DIRECTORY DIRECTORY on local storage where ctdbd keep internal state TDB files. This directory is local for each node and should not be stored on the shared cluster filesystem. This directory would usually be /var/ctdb/state --event-script-dir=DIRECTORY DIRECTORY where the CTDB event scripts are stored. See the EVENT SCRIPTS section in ctdb 7 for more information. Default is CTDB_BASE/events.d, so usually /etc/ctdb/events.d, which is part of the CTDB installation. --logfile=FILENAME FILENAME where ctdbd will write its log. This is usually /var/log/log.ctdb. --log-ringbuf-size=NUM Set the size of the log ringbuffer to NUM entries. CTDB uses an in-memory ringbuffer containing NUM most recent log entries for all log levels (except DEBUG). The ringbugger can be useful for extracting detailed logs even if some entries are not logged to the regular logs. Use the ctdb getlog command to retrieve log entries from the ringbuffer. --lvs This option is used to activate the LVS capability on a CTDB node. Please see the LVS section in ctdb 7 for more information. --max-persistent-check-errors=NUM NUM specifies the maximum number of health check failures allowed for persistent databases during startup. The default value is 0. Setting this to non-zero allows a node with unhealthy persistent databases to startup and join the cluster as long as there is another node with healthy persistent databases. --nlist=FILENAME FILENAME containing a list of the private IP addresses, one per line, for each node in the cluster. This file must be the same on each node in the cluster. Default is CTDB_BASE/nodes, so usually /etc/ctdb/nodes. --no-lmaster This argument specifies that this node can NOT become an lmaster for records in the database. This means that it will never show up in the vnnmap. This feature is primarily used for making a cluster span across a WAN link and use CTDB as a WAN-accelerator. Please see the REMOTE CLUSTER NODES section in ctdb 7 for more information. --no-recmaster This argument specifies that this node can NOT become a recmaster for the database. This feature is primarily used for making a cluster span across a WAN link and use CTDB as a WAN-accelerator. Please see the REMOTE CLUSTER NODES section in ctdb 7 for more information. --notification-script=FILENAME FILENAME specifying a script to be invoked by ctdbd when certain state changes occur. This file is usually /etc/ctdb/notify.sh. Please see the NOTIFICATION SCRIPT section in ctdb 7 for more information. --pidfile=FILENAME FILENAME for file containing process ID of main CTDB daemon. This file is automatically created and removed by CTDB. The default is to not create a PID file. --public_addresses=FILENAME FILENAME specifying a file containing the public IP addresses to use on the cluster when CTDB should use IP takeover. This file contains a list of IP addresses, netmasks and interfaces. CTDB will distribute these public IP addresses appropriately across the available nodes. The IP addresses specified in this file can differ across nodes. This is usually the file /etc/ctdb/public_addresses --public-interface=INTERFACE INTERFACE on which to attach public IP addresses or on which to attach the single-public-ip when used. When using public IP addresses, this is only required if interfaces are not explicitly specified in the public addresses file. --reclock=FILENAME FILENAME is the name of the recovery lock file stored in shared storage that ctdbd uses to prevent split brains from occuring. It is possible to run CTDB without a recovery lock file, but then there will be no protection against split brain if the cluster/network becomes partitioned. Using CTDB without a reclock file is strongly discouraged. --single-public-ip=IPADDR IPADDR specifies the single IP that CTDB will use in conjuction with LVS. Please see the LVS section in ctdb 7 for more information. --start-as-disabled This makes ctdbd start in the DISABLED state. To allow the node to host public IP addresses and services, it must be manually enabled using the ctdb enable command. Please see the NODE STATES section in ctdb 7 for more information about the DISABLED state. --start-as-stopped This makes ctdbd start in the STOPPED state. To allow the node to take part in the cluster it must be manually continued with the the ctdb enable command. Please see the NODE STATES section in ctdb 7 for more information about the STOPPED state. --syslog Send log messages to syslog instead of the CTDB logfile. This option overrides --logfile. The default is to log to a file. --transport=tcp|infiniband This option specifies which transport to use for ctdbd internode communications. The default is "tcp". The "infiniband" support is not regularly tested. -?, --help Display a summary of options. DEBUGGING OPTIONS -i, --interactive Enable interactive mode. This will make ctdbd run in the foreground and not detach from the terminal. By default ctdbd will detach itself and run in the background as a daemon. --listen=IPADDR This specifies which IP address that ctdbd will bind to. By default ctdbd will bind to the first address it finds in the /etc/ctdb/nodes file that is also present on the local system. This option is only required when you want to run multiple ctdbd daemons/nodes on the same physical host in which case there would be multiple entries in /etc/ctdb/nodes that would match a local interface. --nopublicipcheck This option is used when testing with multiple local daemons on a single machine. It disables checks related to public IP addresses. --nosetsched This is a debugging option. This option is only used when debugging ctdbd. Normally ctdbd will change its scheduler to run as a real-time process. This is the default mode for a normal ctdbd operation to gurarantee that ctdbd always gets the CPU cycles that it needs. This option is used to tell ctdbd to not run as a real-time process and instead run ctdbd as a normal userspace process. This is useful for debugging and when you want to run ctdbd under valgrind or gdb. (You don't want to attach valgrind or gdb to a real-time process.) --socket=FILENAME FILENAME specifies the name of the Unix domain socket that ctdbd will create. This socket is used by local clients to communicate with ctdbd. The default is /tmp/ctdb.socket . You only need to use this option if you plan to run multiple ctdbd daemons on the same physical host, usually for testing. --script-log-level=DEBUGLEVEL This option sets the debug level of event script output to DEBUGLEVEL. The default is ERR (0). See the DEBUG LEVELS section in ctdb 7 for more information. --sloppy-start This is debugging option. This speeds up the initial recovery during startup at the expense of some consistency checking. Don't use this option in production. --torture This option is only used for development and testing of CTDB. It adds artificial errors and failures to the common codepaths in ctdbd to verify that ctdbd can recover correctly from failures. Do not use this option unless you are developing and testing new functionality in CTDB. --valgrinding This is a debugging option. This option is only used when debugging ctdbd. This enables additional debugging capabilities and implies --nosetsched. SEE ALSO ctdb 1, ctdbd_wrapper 1, onnode 1, ctdb 7, ctdb-tunables 7, This documentation was written by Ronnie Sahlberg, Amitay Isaacs, Martin Schwenke 2007 Andrew Tridgell Ronnie Sahlberg This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb-2.5.1.dfsg/doc/ctdb-tunables.70000644000175000017500000004341512245332463016626 0ustar mathieumathieu'\" t .\" Title: ctdb-tunables .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "CTDB\-TUNABLES" "7" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ctdb-tunables \- CTDB tunable configuration variables .SH "DESCRIPTION" .PP CTDB\*(Aqs behaviour can be configured by setting run\-time tunable variables\&. This lists and describes all tunables\&. See the \fBctdb\fR(1)\fBlistvars\fR, \fBsetvar\fR and \fBgetvar\fR commands for more details\&. .SS "MaxRedirectCount" .PP Default: 3 .PP If we are not the DMASTER and need to fetch a record across the network we first send the request to the LMASTER after which the record is passed onto the current DMASTER\&. If the DMASTER changes before the request has reached that node, the request will be passed onto the "next" DMASTER\&. For very hot records that migrate rapidly across the cluster this can cause a request to "chase" the record for many hops before it catches up with the record\&. this is how many hops we allow trying to chase the DMASTER before we switch back to the LMASTER again to ask for new directions\&. .PP When chasing a record, this is how many hops we will chase the record for before going back to the LMASTER to ask for new guidance\&. .SS "SeqnumInterval" .PP Default: 1000 .PP Some databases have seqnum tracking enabled, so that samba will be able to detect asynchronously when there has been updates to the database\&. Everytime a database is updated its sequence number is increased\&. .PP This tunable is used to specify in \*(Aqms\*(Aq how frequently ctdb will send out updates to remote nodes to inform them that the sequence number is increased\&. .SS "ControlTimeout" .PP Default: 60 .PP This is the default setting for timeout for when sending a control message to either the local or a remote ctdb daemon\&. .SS "TraverseTimeout" .PP Default: 20 .PP This setting controls how long we allow a traverse process to run\&. After this timeout triggers, the main ctdb daemon will abort the traverse if it has not yet finished\&. .SS "KeepaliveInterval" .PP Default: 5 .PP How often in seconds should the nodes send keepalives to eachother\&. .SS "KeepaliveLimit" .PP Default: 5 .PP After how many keepalive intervals without any traffic should a node wait until marking the peer as DISCONNECTED\&. .PP If a node has hung, it can thus take KeepaliveInterval*(KeepaliveLimit+1) seconds before we determine that the node is DISCONNECTED and that we require a recovery\&. This limitshould not be set too high since we want a hung node to be detectec, and expunged from the cluster well before common CIFS timeouts (45\-90 seconds) kick in\&. .SS "RecoverTimeout" .PP Default: 20 .PP This is the default setting for timeouts for controls when sent from the recovery daemon\&. We allow longer control timeouts from the recovery daemon than from normal use since the recovery dameon often use controls that can take a lot longer than normal controls\&. .SS "RecoverInterval" .PP Default: 1 .PP How frequently in seconds should the recovery daemon perform the consistency checks that determine if we need to perform a recovery or not\&. .SS "ElectionTimeout" .PP Default: 3 .PP When electing a new recovery master, this is how many seconds we allow the election to take before we either deem the election finished or we fail the election and start a new one\&. .SS "TakeoverTimeout" .PP Default: 9 .PP This is how many seconds we allow controls to take for IP failover events\&. .SS "MonitorInterval" .PP Default: 15 .PP How often should ctdb run the event scripts to check for a nodes health\&. .SS "TickleUpdateInterval" .PP Default: 20 .PP How often will ctdb record and store the "tickle" information used to kickstart stalled tcp connections after a recovery\&. .SS "EventScriptTimeout" .PP Default: 20 .PP How long should ctdb let an event script run before aborting it and marking the node unhealthy\&. .SS "EventScriptTimeoutCount" .PP Default: 1 .PP How many events in a row needs to timeout before we flag the node UNHEALTHY\&. This setting is useful if your scripts can not be written so that they do not hang for benign reasons\&. .SS "EventScriptUnhealthyOnTimeout" .PP Default: 0 .PP This setting can be be used to make ctdb never become UNHEALTHY if your eventscripts keep hanging/timing out\&. .SS "RecoveryGracePeriod" .PP Default: 120 .PP During recoveries, if a node has not caused recovery failures during the last grace period, any records of transgressions that the node has caused recovery failures will be forgiven\&. This resets the ban\-counter back to zero for that node\&. .SS "RecoveryBanPeriod" .PP Default: 300 .PP If a node becomes banned causing repetitive recovery failures\&. The node will eventually become banned from the cluster\&. This controls how long the culprit node will be banned from the cluster before it is allowed to try to join the cluster again\&. Don\*(Aqt set to small\&. A node gets banned for a reason and it is usually due to real problems with the node\&. .SS "DatabaseHashSize" .PP Default: 100001 .PP Size of the hash chains for the local store of the tdbs that ctdb manages\&. .SS "DatabaseMaxDead" .PP Default: 5 .PP How many dead records per hashchain in the TDB database do we allow before the freelist needs to be processed\&. .SS "RerecoveryTimeout" .PP Default: 10 .PP Once a recovery has completed, no additional recoveries are permitted until this timeout has expired\&. .SS "EnableBans" .PP Default: 1 .PP When set to 0, this disables BANNING completely in the cluster and thus nodes can not get banned, even it they break\&. Don\*(Aqt set to 0 unless you know what you are doing\&. You should set this to the same value on all nodes to avoid unexpected behaviour\&. .SS "DeterministicIPs" .PP Default: 0 .PP When enabled, this tunable makes ctdb try to keep public IP addresses locked to specific nodes as far as possible\&. This makes it easier for debugging since you can know that as long as all nodes are healthy public IP X will always be hosted by node Y\&. .PP The cost of using deterministic IP address assignment is that it disables part of the logic where ctdb tries to reduce the number of public IP assignment changes in the cluster\&. This tunable may increase the number of IP failover/failbacks that are performed on the cluster by a small margin\&. .SS "LCP2PublicIPs" .PP Default: 1 .PP When enabled this switches ctdb to use the LCP2 ip allocation algorithm\&. .SS "ReclockPingPeriod" .PP Default: x .PP Obsolete .SS "NoIPFailback" .PP Default: 0 .PP When set to 1, ctdb will not perform failback of IP addresses when a node becomes healthy\&. Ctdb WILL perform failover of public IP addresses when a node becomes UNHEALTHY, but when the node becomes HEALTHY again, ctdb will not fail the addresses back\&. .PP Use with caution! Normally when a node becomes available to the cluster ctdb will try to reassign public IP addresses onto the new node as a way to distribute the workload evenly across the clusternode\&. Ctdb tries to make sure that all running nodes have approximately the same number of public addresses it hosts\&. .PP When you enable this tunable, CTDB will no longer attempt to rebalance the cluster by failing IP addresses back to the new nodes\&. An unbalanced cluster will therefore remain unbalanced until there is manual intervention from the administrator\&. When this parameter is set, you can manually fail public IP addresses over to the new node(s) using the \*(Aqctdb moveip\*(Aq command\&. .SS "DisableIPFailover" .PP Default: 0 .PP When enabled, ctdb will not perform failover or failback\&. Even if a node fails while holding public IPs, ctdb will not recover the IPs or assign them to another node\&. .PP When you enable this tunable, CTDB will no longer attempt to recover the cluster by failing IP addresses over to other nodes\&. This leads to a service outage until the administrator has manually performed failover to replacement nodes using the \*(Aqctdb moveip\*(Aq command\&. .SS "NoIPTakeover" .PP Default: 0 .PP When set to 1, ctdb will not allow IP addresses to be failed over onto this node\&. Any IP addresses that the node currently hosts will remain on the node but no new IP addresses can be failed over to the node\&. .SS "NoIPHostOnAllDisabled" .PP Default: 0 .PP If no nodes are healthy then by default ctdb will happily host public IPs on disabled (unhealthy or administratively disabled) nodes\&. This can cause problems, for example if the underlying cluster filesystem is not mounted\&. When set to 1 on a node and that node is disabled it, any IPs hosted by this node will be released and the node will not takeover any IPs until it is no longer disabled\&. .SS "DBRecordCountWarn" .PP Default: 100000 .PP When set to non\-zero, ctdb will log a warning when we try to recover a database with more than this many records\&. This will produce a warning if a database grows uncontrollably with orphaned records\&. .SS "DBRecordSizeWarn" .PP Default: 10000000 .PP When set to non\-zero, ctdb will log a warning when we try to recover a database where a single record is bigger than this\&. This will produce a warning if a database record grows uncontrollably with orphaned sub\-records\&. .SS "DBSizeWarn" .PP Default: 1000000000 .PP When set to non\-zero, ctdb will log a warning when we try to recover a database bigger than this\&. This will produce a warning if a database grows uncontrollably\&. .SS "VerboseMemoryNames" .PP Default: 0 .PP This feature consumes additional memory\&. when used the talloc library will create more verbose names for all talloc allocated objects\&. .SS "RecdPingTimeout" .PP Default: 60 .PP If the main dameon has not heard a "ping" from the recovery dameon for this many seconds, the main dameon will log a message that the recovery daemon is potentially hung\&. .SS "RecdFailCount" .PP Default: 10 .PP If the recovery daemon has failed to ping the main dameon for this many consecutive intervals, the main daemon will consider the recovery daemon as hung and will try to restart it to recover\&. .SS "LogLatencyMs" .PP Default: 0 .PP When set to non\-zero, this will make the main daemon log any operation that took longer than this value, in \*(Aqms\*(Aq, to complete\&. These include "how long time a lockwait child process needed", "how long time to write to a persistent database" but also "how long did it take to get a response to a CALL from a remote node"\&. .SS "RecLockLatencyMs" .PP Default: 1000 .PP When using a reclock file for split brain prevention, if set to non\-zero this tunable will make the recovery dameon log a message if the fcntl() call to lock/testlock the recovery file takes longer than this number of ms\&. .SS "RecoveryDropAllIPs" .PP Default: 120 .PP If we have been stuck in recovery, or stopped, or banned, mode for this many seconds we will force drop all held public addresses\&. .SS "VerifyRecoveryLock" .PP Default: 1 .PP Should we take a fcntl() lock on the reclock file to verify that we are the sole recovery master node on the cluster or not\&. .SS "VacuumInterval" .PP Default: 10 .PP Periodic interval in seconds when vacuuming is triggered for volatile databases\&. .SS "VacuumMaxRunTime" .PP Default: 120 .PP The maximum time in seconds for which the vacuuming process is allowed to run\&. If vacuuming process takes longer than this value, then the vacuuming process is terminated\&. .SS "RepackLimit" .PP Default: 10000 .PP During vacuuming, if the number of freelist records are more than \fIRepackLimit\fR, then databases are repacked to get rid of the freelist records to avoid fragmentation\&. .PP Databases are repacked only if both \fIRepackLimit\fR and \fIVacuumLimit\fR are exceeded\&. .SS "VacuumLimit" .PP Default: 5000 .PP During vacuuming, if the number of deleted records are more than \fIVacuumLimit\fR, then databases are repacked to avoid fragmentation\&. .PP Databases are repacked only if both \fIRepackLimit\fR and \fIVacuumLimit\fR are exceeded\&. .SS "VacuumFastPathCount" .PP Default: 60 .PP When a record is deleted, it is marked for deletion during vacuuming\&. Vacuuming process usually processes this list to purge the records from the database\&. If the number of records marked for deletion are more than VacuumFastPathCount, then vacuuming process will scan the complete database for empty records instead of using the list of records marked for deletion\&. .SS "DeferredAttachTO" .PP Default: 120 .PP When databases are frozen we do not allow clients to attach to the databases\&. Instead of returning an error immediately to the application the attach request from the client is deferred until the database becomes available again at which stage we respond to the client\&. .PP This timeout controls how long we will defer the request from the client before timing it out and returning an error to the client\&. .SS "HopcountMakeSticky" .PP Default: 50 .PP If the database is set to \*(AqSTICKY\*(Aq mode, using the \*(Aqctdb setdbsticky\*(Aq command, any record that is seen as very hot and migrating so fast that hopcount surpasses 50 is set to become a STICKY record for StickyDuration seconds\&. This means that after each migration the record will be kept on the node and prevented from being migrated off the node\&. .PP This setting allows one to try to identify such records and stop them from migrating across the cluster so fast\&. This will improve performance for certain workloads, such as locking\&.tdb if many clients are opening/closing the same file concurrently\&. .SS "StickyDuration" .PP Default: 600 .PP Once a record has been found to be fetch\-lock hot and has been flagged to become STICKY, this is for how long, in seconds, the record will be flagged as a STICKY record\&. .SS "StickyPindown" .PP Default: 200 .PP Once a STICKY record has been migrated onto a node, it will be pinned down on that node for this number of ms\&. Any request from other nodes to migrate the record off the node will be deferred until the pindown timer expires\&. .SS "StatHistoryInterval" .PP Default: 1 .PP Granularity of the statistics collected in the statistics history\&. .SS "AllowClientDBAttach" .PP Default: 1 .PP When set to 0, clients are not allowed to attach to any databases\&. This can be used to temporarily block any new processes from attaching to and accessing the databases\&. .SS "RecoverPDBBySeqNum" .PP Default: 1 .PP When set to zero, database recovery for persistent databases is record\-by\-record and recovery process simply collects the most recent version of every individual record\&. .PP When set to non\-zero, persistent databases will instead be recovered as a whole db and not by individual records\&. The node that contains the highest value stored in the record "__db_sequence_number__" is selected and the copy of that nodes database is used as the recovered database\&. .PP By default, recovery of persistent databses is done using __db_sequence_number__ record\&. .SS "FetchCollapse" .PP Default: 1 .PP When many clients across many nodes try to access the same record at the same time this can lead to a fetch storm where the record becomes very active and bounces between nodes very fast\&. This leads to high CPU utilization of the ctdbd daemon, trying to bounce that record around very fast, and poor performance\&. .PP This parameter is used to activate a fetch\-collapse\&. A fetch\-collapse is when we track which records we have requests in flight so that we only keep one request in flight from a certain node, even if multiple smbd processes are attemtping to fetch the record at the same time\&. This can improve performance and reduce CPU utilization for certain workloads\&. .PP This timeout controls if we should collapse multiple fetch operations of the same record into a single request and defer all duplicates or not\&. .SS "Samba3AvoidDeadlocks" .PP Default: 0 .PP Enable code that prevents deadlocks with Samba (only for Samba 3\&.x)\&. .PP This should be set to 1 when using Samba version 3\&.x to enable special code in CTDB to avoid deadlock with Samba version 3\&.x\&. This code is not required for Samba version 4\&.x and must not be enabled for Samba 4\&.x\&. .SH "SEE ALSO" .PP \fBctdb\fR(1), \fBctdbd\fR(1), \fBctdbd.conf\fR(5), \fBctdb\fR(7), \m[blue]\fB\%http://ctdb.samba.org/\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Ronnie Sahlberg, Amitay Isaacs, Martin Schwenke .SH "COPYRIGHT" .br Copyright \(co 2007 Andrew Tridgell, Ronnie Sahlberg .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp ctdb-2.5.1.dfsg/doc/ctdbd_wrapper.1.html0000644000175000017500000000332612245332460017646 0ustar mathieumathieuctdbd_wrapper

Name

ctdbd_wrapper — Wrapper for ctdbd

Synopsis

ctdbd_wrapper {PIDFILE} { start | stop }

DESCRIPTION

ctdbd_wrapper is used to start or stop the main CTDB daemon.

PIDFILE specifies the location of the file containing the PID of the main CTDB daemon.

ctdbd_wrapper constructs command-line options for ctdbd from configuration variables specified in ctdbd.conf(5).

See ctdb(7) for an overview of CTDB.

SEE ALSO

ctdbd(1), ctdbd.conf(5), ctdb(7), http://ctdb.samba.org/

ctdb-2.5.1.dfsg/doc/ctdb-tunables.7.xml0000644000175000017500000005541212245023514017417 0ustar mathieumathieu ctdb-tunables 7 ctdb CTDB - clustered TDB database ctdb-tunables CTDB tunable configuration variables DESCRIPTION CTDB's behaviour can be configured by setting run-time tunable variables. This lists and describes all tunables. See the ctdb 1 listvars, setvar and getvar commands for more details. MaxRedirectCount Default: 3 If we are not the DMASTER and need to fetch a record across the network we first send the request to the LMASTER after which the record is passed onto the current DMASTER. If the DMASTER changes before the request has reached that node, the request will be passed onto the "next" DMASTER. For very hot records that migrate rapidly across the cluster this can cause a request to "chase" the record for many hops before it catches up with the record. this is how many hops we allow trying to chase the DMASTER before we switch back to the LMASTER again to ask for new directions. When chasing a record, this is how many hops we will chase the record for before going back to the LMASTER to ask for new guidance. SeqnumInterval Default: 1000 Some databases have seqnum tracking enabled, so that samba will be able to detect asynchronously when there has been updates to the database. Everytime a database is updated its sequence number is increased. This tunable is used to specify in 'ms' how frequently ctdb will send out updates to remote nodes to inform them that the sequence number is increased. ControlTimeout Default: 60 This is the default setting for timeout for when sending a control message to either the local or a remote ctdb daemon. TraverseTimeout Default: 20 This setting controls how long we allow a traverse process to run. After this timeout triggers, the main ctdb daemon will abort the traverse if it has not yet finished. KeepaliveInterval Default: 5 How often in seconds should the nodes send keepalives to eachother. KeepaliveLimit Default: 5 After how many keepalive intervals without any traffic should a node wait until marking the peer as DISCONNECTED. If a node has hung, it can thus take KeepaliveInterval*(KeepaliveLimit+1) seconds before we determine that the node is DISCONNECTED and that we require a recovery. This limitshould not be set too high since we want a hung node to be detectec, and expunged from the cluster well before common CIFS timeouts (45-90 seconds) kick in. RecoverTimeout Default: 20 This is the default setting for timeouts for controls when sent from the recovery daemon. We allow longer control timeouts from the recovery daemon than from normal use since the recovery dameon often use controls that can take a lot longer than normal controls. RecoverInterval Default: 1 How frequently in seconds should the recovery daemon perform the consistency checks that determine if we need to perform a recovery or not. ElectionTimeout Default: 3 When electing a new recovery master, this is how many seconds we allow the election to take before we either deem the election finished or we fail the election and start a new one. TakeoverTimeout Default: 9 This is how many seconds we allow controls to take for IP failover events. MonitorInterval Default: 15 How often should ctdb run the event scripts to check for a nodes health. TickleUpdateInterval Default: 20 How often will ctdb record and store the "tickle" information used to kickstart stalled tcp connections after a recovery. EventScriptTimeout Default: 20 How long should ctdb let an event script run before aborting it and marking the node unhealthy. EventScriptTimeoutCount Default: 1 How many events in a row needs to timeout before we flag the node UNHEALTHY. This setting is useful if your scripts can not be written so that they do not hang for benign reasons. EventScriptUnhealthyOnTimeout Default: 0 This setting can be be used to make ctdb never become UNHEALTHY if your eventscripts keep hanging/timing out. RecoveryGracePeriod Default: 120 During recoveries, if a node has not caused recovery failures during the last grace period, any records of transgressions that the node has caused recovery failures will be forgiven. This resets the ban-counter back to zero for that node. RecoveryBanPeriod Default: 300 If a node becomes banned causing repetitive recovery failures. The node will eventually become banned from the cluster. This controls how long the culprit node will be banned from the cluster before it is allowed to try to join the cluster again. Don't set to small. A node gets banned for a reason and it is usually due to real problems with the node. DatabaseHashSize Default: 100001 Size of the hash chains for the local store of the tdbs that ctdb manages. DatabaseMaxDead Default: 5 How many dead records per hashchain in the TDB database do we allow before the freelist needs to be processed. RerecoveryTimeout Default: 10 Once a recovery has completed, no additional recoveries are permitted until this timeout has expired. EnableBans Default: 1 When set to 0, this disables BANNING completely in the cluster and thus nodes can not get banned, even it they break. Don't set to 0 unless you know what you are doing. You should set this to the same value on all nodes to avoid unexpected behaviour. DeterministicIPs Default: 0 When enabled, this tunable makes ctdb try to keep public IP addresses locked to specific nodes as far as possible. This makes it easier for debugging since you can know that as long as all nodes are healthy public IP X will always be hosted by node Y. The cost of using deterministic IP address assignment is that it disables part of the logic where ctdb tries to reduce the number of public IP assignment changes in the cluster. This tunable may increase the number of IP failover/failbacks that are performed on the cluster by a small margin. LCP2PublicIPs Default: 1 When enabled this switches ctdb to use the LCP2 ip allocation algorithm. ReclockPingPeriod Default: x Obsolete NoIPFailback Default: 0 When set to 1, ctdb will not perform failback of IP addresses when a node becomes healthy. Ctdb WILL perform failover of public IP addresses when a node becomes UNHEALTHY, but when the node becomes HEALTHY again, ctdb will not fail the addresses back. Use with caution! Normally when a node becomes available to the cluster ctdb will try to reassign public IP addresses onto the new node as a way to distribute the workload evenly across the clusternode. Ctdb tries to make sure that all running nodes have approximately the same number of public addresses it hosts. When you enable this tunable, CTDB will no longer attempt to rebalance the cluster by failing IP addresses back to the new nodes. An unbalanced cluster will therefore remain unbalanced until there is manual intervention from the administrator. When this parameter is set, you can manually fail public IP addresses over to the new node(s) using the 'ctdb moveip' command. DisableIPFailover Default: 0 When enabled, ctdb will not perform failover or failback. Even if a node fails while holding public IPs, ctdb will not recover the IPs or assign them to another node. When you enable this tunable, CTDB will no longer attempt to recover the cluster by failing IP addresses over to other nodes. This leads to a service outage until the administrator has manually performed failover to replacement nodes using the 'ctdb moveip' command. NoIPTakeover Default: 0 When set to 1, ctdb will not allow IP addresses to be failed over onto this node. Any IP addresses that the node currently hosts will remain on the node but no new IP addresses can be failed over to the node. NoIPHostOnAllDisabled Default: 0 If no nodes are healthy then by default ctdb will happily host public IPs on disabled (unhealthy or administratively disabled) nodes. This can cause problems, for example if the underlying cluster filesystem is not mounted. When set to 1 on a node and that node is disabled it, any IPs hosted by this node will be released and the node will not takeover any IPs until it is no longer disabled. DBRecordCountWarn Default: 100000 When set to non-zero, ctdb will log a warning when we try to recover a database with more than this many records. This will produce a warning if a database grows uncontrollably with orphaned records. DBRecordSizeWarn Default: 10000000 When set to non-zero, ctdb will log a warning when we try to recover a database where a single record is bigger than this. This will produce a warning if a database record grows uncontrollably with orphaned sub-records. DBSizeWarn Default: 1000000000 When set to non-zero, ctdb will log a warning when we try to recover a database bigger than this. This will produce a warning if a database grows uncontrollably. VerboseMemoryNames Default: 0 This feature consumes additional memory. when used the talloc library will create more verbose names for all talloc allocated objects. RecdPingTimeout Default: 60 If the main dameon has not heard a "ping" from the recovery dameon for this many seconds, the main dameon will log a message that the recovery daemon is potentially hung. RecdFailCount Default: 10 If the recovery daemon has failed to ping the main dameon for this many consecutive intervals, the main daemon will consider the recovery daemon as hung and will try to restart it to recover. LogLatencyMs Default: 0 When set to non-zero, this will make the main daemon log any operation that took longer than this value, in 'ms', to complete. These include "how long time a lockwait child process needed", "how long time to write to a persistent database" but also "how long did it take to get a response to a CALL from a remote node". RecLockLatencyMs Default: 1000 When using a reclock file for split brain prevention, if set to non-zero this tunable will make the recovery dameon log a message if the fcntl() call to lock/testlock the recovery file takes longer than this number of ms. RecoveryDropAllIPs Default: 120 If we have been stuck in recovery, or stopped, or banned, mode for this many seconds we will force drop all held public addresses. VerifyRecoveryLock Default: 1 Should we take a fcntl() lock on the reclock file to verify that we are the sole recovery master node on the cluster or not. VacuumInterval Default: 10 Periodic interval in seconds when vacuuming is triggered for volatile databases. VacuumMaxRunTime Default: 120 The maximum time in seconds for which the vacuuming process is allowed to run. If vacuuming process takes longer than this value, then the vacuuming process is terminated. RepackLimit Default: 10000 During vacuuming, if the number of freelist records are more than RepackLimit, then databases are repacked to get rid of the freelist records to avoid fragmentation. Databases are repacked only if both RepackLimit and VacuumLimit are exceeded. VacuumLimit Default: 5000 During vacuuming, if the number of deleted records are more than VacuumLimit, then databases are repacked to avoid fragmentation. Databases are repacked only if both RepackLimit and VacuumLimit are exceeded. VacuumFastPathCount Default: 60 When a record is deleted, it is marked for deletion during vacuuming. Vacuuming process usually processes this list to purge the records from the database. If the number of records marked for deletion are more than VacuumFastPathCount, then vacuuming process will scan the complete database for empty records instead of using the list of records marked for deletion. DeferredAttachTO Default: 120 When databases are frozen we do not allow clients to attach to the databases. Instead of returning an error immediately to the application the attach request from the client is deferred until the database becomes available again at which stage we respond to the client. This timeout controls how long we will defer the request from the client before timing it out and returning an error to the client. HopcountMakeSticky Default: 50 If the database is set to 'STICKY' mode, using the 'ctdb setdbsticky' command, any record that is seen as very hot and migrating so fast that hopcount surpasses 50 is set to become a STICKY record for StickyDuration seconds. This means that after each migration the record will be kept on the node and prevented from being migrated off the node. This setting allows one to try to identify such records and stop them from migrating across the cluster so fast. This will improve performance for certain workloads, such as locking.tdb if many clients are opening/closing the same file concurrently. StickyDuration Default: 600 Once a record has been found to be fetch-lock hot and has been flagged to become STICKY, this is for how long, in seconds, the record will be flagged as a STICKY record. StickyPindown Default: 200 Once a STICKY record has been migrated onto a node, it will be pinned down on that node for this number of ms. Any request from other nodes to migrate the record off the node will be deferred until the pindown timer expires. StatHistoryInterval Default: 1 Granularity of the statistics collected in the statistics history. AllowClientDBAttach Default: 1 When set to 0, clients are not allowed to attach to any databases. This can be used to temporarily block any new processes from attaching to and accessing the databases. RecoverPDBBySeqNum Default: 1 When set to zero, database recovery for persistent databases is record-by-record and recovery process simply collects the most recent version of every individual record. When set to non-zero, persistent databases will instead be recovered as a whole db and not by individual records. The node that contains the highest value stored in the record "__db_sequence_number__" is selected and the copy of that nodes database is used as the recovered database. By default, recovery of persistent databses is done using __db_sequence_number__ record. FetchCollapse Default: 1 When many clients across many nodes try to access the same record at the same time this can lead to a fetch storm where the record becomes very active and bounces between nodes very fast. This leads to high CPU utilization of the ctdbd daemon, trying to bounce that record around very fast, and poor performance. This parameter is used to activate a fetch-collapse. A fetch-collapse is when we track which records we have requests in flight so that we only keep one request in flight from a certain node, even if multiple smbd processes are attemtping to fetch the record at the same time. This can improve performance and reduce CPU utilization for certain workloads. This timeout controls if we should collapse multiple fetch operations of the same record into a single request and defer all duplicates or not. Samba3AvoidDeadlocks Default: 0 Enable code that prevents deadlocks with Samba (only for Samba 3.x). This should be set to 1 when using Samba version 3.x to enable special code in CTDB to avoid deadlock with Samba version 3.x. This code is not required for Samba version 4.x and must not be enabled for Samba 4.x. SEE ALSO ctdb 1, ctdbd 1, ctdbd.conf 5, ctdb 7, This documentation was written by Ronnie Sahlberg, Amitay Isaacs, Martin Schwenke 2007 Andrew Tridgell Ronnie Sahlberg This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb-2.5.1.dfsg/doc/ctdb.10000644000175000017500000013052212245332457015004 0ustar mathieumathieu'\" t .\" Title: ctdb .\" Author: .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/27/2013 .\" Manual: CTDB - clustered TDB database .\" Source: ctdb .\" Language: English .\" .TH "CTDB" "1" "11/27/2013" "ctdb" "CTDB \- clustered TDB database" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ctdb \- CTDB management utility .SH "SYNOPSIS" .HP \w'\fBctdb\fR\ 'u \fBctdb\fR [\fIOPTION\fR...] {\fICOMMAND\fR} [\fICOMMAND\-ARGS\fR] .SH "DESCRIPTION" .PP ctdb is a utility to view and manage a CTDB cluster\&. .PP The following terms are used when referring to nodes in a cluster: .PP PNN .RS 4 Physical Node Number\&. The physical node number is an integer that describes the node in the cluster\&. The first node has physical node number 0\&. in a cluster\&. .RE .PP PNN\-LIST .RS 4 This is either a single PNN, a comma\-separate list of PNNs or "all"\&. .RE .PP Commands that reference a database have a \fIDB\fR argument\&. This is either a database name, such as locking\&.tdb or a database ID such as "0x42fe72c5"\&. .SH "OPTIONS" .PP \-n \fIPNN\-LIST\fR .RS 4 The nodes specified by PNN\-LIST should be queried for the requested information\&. Default is to query the daemon running on the local host\&. .RE .PP \-Y .RS 4 Produce output in machine readable form for easier parsing by scripts\&. Not all commands support this option\&. .RE .PP \-t \fITIMEOUT\fR .RS 4 Indicates that ctdb should wait up to TIMEOUT seconds for a response to most commands sent to the CTDB daemon\&. The default is 10 seconds\&. .RE .PP \-T \fITIMELIMIT\fR .RS 4 Indicates that TIMELIMIT is the maximum run time (in seconds) for the ctdb command\&. When TIMELIMIT is exceeded the ctdb command will terminate with an error\&. The default is 120 seconds\&. .RE .PP \-? \-\-help .RS 4 Print some help text to the screen\&. .RE .PP \-\-usage .RS 4 Print useage information to the screen\&. .RE .PP \-d \-\-debug=\fIDEBUGLEVEL\fR .RS 4 Change the debug level for the command\&. Default is ERR (0)\&. .RE .PP \-\-socket=\fIFILENAME\fR .RS 4 Specify that FILENAME is the name of the Unix domain socket to use when connecting to the local CTDB daemon\&. The default is /tmp/ctdb\&.socket\&. .RE .SH "ADMINISTRATIVE COMMANDS" .PP These are commands used to monitor and administer a CTDB cluster\&. .SS "pnn" .PP This command displays the PNN of the current node\&. .SS "xpnn" .PP This command displays the PNN of the current node without contacting the CTDB daemon\&. It parses the nodes file directly, so can produce unexpected output if the nodes file has been edited but has not been reloaded\&. .SS "status" .PP This command shows the current status of all CTDB nodes based on information from the queried node\&. .PP Note: If the the queried node is INACTIVE then the status might not be current\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNode status\fR .RS 4 .PP This includes the number of physical nodes and the status of each node\&. See \fBctdb\fR(7) for information about node states\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBGeneration\fR .RS 4 .PP The generation id is a number that indicates the current generation of a cluster instance\&. Each time a cluster goes through a reconfiguration or a recovery its generation id will be changed\&. .PP This number does not have any particular meaning other than to keep track of when a cluster has gone through a recovery\&. It is a random number that represents the current instance of a ctdb cluster and its databases\&. The CTDB daemon uses this number internally to be able to tell when commands to operate on the cluster and the databases was issued in a different generation of the cluster, to ensure that commands that operate on the databases will not survive across a cluster database recovery\&. After a recovery, all old outstanding commands will automatically become invalid\&. .PP Sometimes this number will be shown as "INVALID"\&. This only means that the ctdbd daemon has started but it has not yet merged with the cluster through a recovery\&. All nodes start with generation "INVALID" and are not assigned a real generation id until they have successfully been merged with a cluster through a recovery\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBVirtual Node Number (VNN) map\fR .RS 4 .PP Consists of the number of virtual nodes and mapping from virtual node numbers to physical node numbers\&. Virtual nodes host CTDB databases\&. Only nodes that are participating in the VNN map can become lmaster or dmaster for database records\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBRecovery mode\fR .RS 4 .PP This is the current recovery mode of the cluster\&. There are two possible modes: .PP NORMAL \- The cluster is fully operational\&. .PP RECOVERY \- The cluster databases have all been frozen, pausing all services while the cluster awaits a recovery process to complete\&. A recovery process should finish within seconds\&. If a cluster is stuck in the RECOVERY state this would indicate a cluster malfunction which needs to be investigated\&. .PP Once the recovery master detects an inconsistency, for example a node becomes disconnected/connected, the recovery daemon will trigger a cluster recovery process, where all databases are remerged across the cluster\&. When this process starts, the recovery master will first "freeze" all databases to prevent applications such as samba from accessing the databases and it will also mark the recovery mode as RECOVERY\&. .PP When the CTDB daemon starts up, it will start in RECOVERY mode\&. Once the node has been merged into a cluster and all databases have been recovered, the node mode will change into NORMAL mode and the databases will be "thawed", allowing samba to access the databases again\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBRecovery master\fR .RS 4 .PP This is the cluster node that is currently designated as the recovery master\&. This node is responsible of monitoring the consistency of the cluster and to perform the actual recovery process when reqired\&. .PP Only one node at a time can be the designated recovery master\&. Which node is designated the recovery master is decided by an election process in the recovery daemons running on each node\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb status Number of nodes:4 pnn:0 192\&.168\&.2\&.200 OK (THIS NODE) pnn:1 192\&.168\&.2\&.201 OK pnn:2 192\&.168\&.2\&.202 OK pnn:3 192\&.168\&.2\&.203 OK Generation:1362079228 Size:4 hash:0 lmaster:0 hash:1 lmaster:1 hash:2 lmaster:2 hash:3 lmaster:3 Recovery mode:NORMAL (0) Recovery master:0 .fi .if n \{\ .RE .\} .RE .SS "nodestatus [\fIPNN\-LIST\fR]" .PP This command is similar to the \fBstatus\fR command\&. It displays the "node status" subset of output\&. The main differences are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The exit code is the bitwise\-OR of the flags for each specified node, while \fBctdb status\fR exits with 0 if it was able to retrieve status for all nodes\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBctdb status\fR provides status information for all nodes\&. \fBctdb nodestatus\fR defaults to providing status for only the current node\&. If PNN\-LIST is provided then status is given for the indicated node(s)\&. .sp By default, \fBctdb nodestatus\fR gathers status from the local node\&. However, if invoked with "\-n all" (or similar) then status is gathered from the given node(s)\&. In particular \fBctdb nodestatus all\fR and \fBctdb nodestatus \-n all\fR will produce different output\&. It is possible to provide 2 different nodespecs (with and without "\-n") but the output is usually confusing! .RE .PP A common invocation in scripts is \fBctdb nodestatus all\fR to check whether all nodes in a cluster are healthy\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb nodestatus pnn:0 10\&.0\&.0\&.30 OK (THIS NODE) # ctdb nodestatus all Number of nodes:2 pnn:0 10\&.0\&.0\&.30 OK (THIS NODE) pnn:1 10\&.0\&.0\&.31 OK .fi .if n \{\ .RE .\} .RE .SS "recmaster" .PP This command shows the pnn of the node which is currently the recmaster\&. .PP Note: If the the queried node is INACTIVE then the status might not be current\&. .SS "uptime" .PP This command shows the uptime for the ctdb daemon\&. When the last recovery or ip\-failover completed and how long it took\&. If the "duration" is shown as a negative number, this indicates that there is a recovery/failover in progress and it started that many seconds ago\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb uptime Current time of node : Thu Oct 29 10:38:54 2009 Ctdbd start time : (000 16:54:28) Wed Oct 28 17:44:26 2009 Time of last recovery/failover: (000 16:53:31) Wed Oct 28 17:45:23 2009 Duration of last recovery/failover: 2\&.248552 seconds .fi .if n \{\ .RE .\} .RE .SS "listnodes" .PP This command shows lists the ip addresses of all the nodes in the cluster\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb listnodes 192\&.168\&.2\&.200 192\&.168\&.2\&.201 192\&.168\&.2\&.202 192\&.168\&.2\&.203 .fi .if n \{\ .RE .\} .RE .SS "natgwlist" .PP Show the current NAT gateway master and the status of all nodes in the current NAT gateway group\&. See the NAT GATEWAY section in \fBctdb\fR(7) for more details\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb natgwlist 0 192\&.168\&.2\&.200 Number of nodes:4 pnn:0 192\&.168\&.2\&.200 OK (THIS NODE) pnn:1 192\&.168\&.2\&.201 OK pnn:2 192\&.168\&.2\&.202 OK pnn:3 192\&.168\&.2\&.203 OK .fi .if n \{\ .RE .\} .RE .SS "ping" .PP This command will "ping" specified CTDB nodes in the cluster to verify that they are running\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb ping \-n all response from 0 time=0\&.000054 sec (3 clients) response from 1 time=0\&.000144 sec (2 clients) response from 2 time=0\&.000105 sec (2 clients) response from 3 time=0\&.000114 sec (2 clients) .fi .if n \{\ .RE .\} .RE .SS "ifaces" .PP This command will display the list of network interfaces, which could host public addresses, along with their status\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb ifaces Interfaces on node 0 name:eth5 link:up references:2 name:eth4 link:down references:0 name:eth3 link:up references:1 name:eth2 link:up references:1 # ctdb ifaces \-Y :Name:LinkStatus:References: :eth5:1:2 :eth4:0:0 :eth3:1:1 :eth2:1:1 .fi .if n \{\ .RE .\} .RE .SS "ip" .PP This command will display the list of public addresses that are provided by the cluster and which physical node is currently serving this ip\&. By default this command will ONLY show those public addresses that are known to the node itself\&. To see the full list of all public ips across the cluster you must use "ctdb ip \-n all"\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb ip Public IPs on node 0 172\&.31\&.91\&.82 node[1] active[] available[eth2,eth3] configured[eth2,eth3] 172\&.31\&.91\&.83 node[0] active[eth3] available[eth2,eth3] configured[eth2,eth3] 172\&.31\&.91\&.84 node[1] active[] available[eth2,eth3] configured[eth2,eth3] 172\&.31\&.91\&.85 node[0] active[eth2] available[eth2,eth3] configured[eth2,eth3] 172\&.31\&.92\&.82 node[1] active[] available[eth5] configured[eth4,eth5] 172\&.31\&.92\&.83 node[0] active[eth5] available[eth5] configured[eth4,eth5] 172\&.31\&.92\&.84 node[1] active[] available[eth5] configured[eth4,eth5] 172\&.31\&.92\&.85 node[0] active[eth5] available[eth5] configured[eth4,eth5] # ctdb ip \-Y :Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces: :172\&.31\&.91\&.82:1::eth2,eth3:eth2,eth3: :172\&.31\&.91\&.83:0:eth3:eth2,eth3:eth2,eth3: :172\&.31\&.91\&.84:1::eth2,eth3:eth2,eth3: :172\&.31\&.91\&.85:0:eth2:eth2,eth3:eth2,eth3: :172\&.31\&.92\&.82:1::eth5:eth4,eth5: :172\&.31\&.92\&.83:0:eth5:eth5:eth4,eth5: :172\&.31\&.92\&.84:1::eth5:eth4,eth5: :172\&.31\&.92\&.85:0:eth5:eth5:eth4,eth5: .fi .if n \{\ .RE .\} .RE .SS "ipinfo \fIIP\fR" .PP This command will display details about the specified public addresses\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb ipinfo 172\&.31\&.92\&.85 Public IP[172\&.31\&.92\&.85] info on node 0 IP:172\&.31\&.92\&.85 CurrentNode:0 NumInterfaces:2 Interface[1]: Name:eth4 Link:down References:0 Interface[2]: Name:eth5 Link:up References:2 (active) .fi .if n \{\ .RE .\} .RE .SS "scriptstatus" .PP This command displays which scripts where run in the previous monitoring cycle and the result of each script\&. If a script failed with an error, causing the node to become unhealthy, the output from that script is also shown\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb scriptstatus 7 scripts were executed last monitoring cycle 00\&.ctdb Status:OK Duration:0\&.056 Tue Mar 24 18:56:57 2009 10\&.interface Status:OK Duration:0\&.077 Tue Mar 24 18:56:57 2009 11\&.natgw Status:OK Duration:0\&.039 Tue Mar 24 18:56:57 2009 20\&.multipathd Status:OK Duration:0\&.038 Tue Mar 24 18:56:57 2009 31\&.clamd Status:DISABLED 40\&.vsftpd Status:OK Duration:0\&.045 Tue Mar 24 18:56:57 2009 41\&.httpd Status:OK Duration:0\&.039 Tue Mar 24 18:56:57 2009 50\&.samba Status:ERROR Duration:0\&.082 Tue Mar 24 18:56:57 2009 OUTPUT:ERROR: Samba tcp port 445 is not responding .fi .if n \{\ .RE .\} .RE .SS "disablescript \fISCRIPT\fR" .PP This command is used to disable an eventscript\&. .PP This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in \*(Aqscriptstatus\*(Aq\&. .SS "enablescript \fISCRIPT\fR" .PP This command is used to enable an eventscript\&. .PP This will take effect the next time the eventscripts are being executed so it can take a short while until this is reflected in \*(Aqscriptstatus\*(Aq\&. .SS "listvars" .PP List all tuneable variables, except the values of the obsolete tunables like VacuumMinInterval\&. The obsolete tunables can be retrieved only explicitly with the "ctdb getvar" command\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb listvars MaxRedirectCount = 3 SeqnumInterval = 1000 ControlTimeout = 60 TraverseTimeout = 20 KeepaliveInterval = 5 KeepaliveLimit = 5 RecoverTimeout = 20 RecoverInterval = 1 ElectionTimeout = 3 TakeoverTimeout = 9 MonitorInterval = 15 TickleUpdateInterval = 20 EventScriptTimeout = 30 EventScriptTimeoutCount = 1 RecoveryGracePeriod = 120 RecoveryBanPeriod = 300 DatabaseHashSize = 100001 DatabaseMaxDead = 5 RerecoveryTimeout = 10 EnableBans = 1 DeterministicIPs = 0 LCP2PublicIPs = 1 ReclockPingPeriod = 60 NoIPFailback = 0 DisableIPFailover = 0 VerboseMemoryNames = 0 RecdPingTimeout = 60 RecdFailCount = 10 LogLatencyMs = 0 RecLockLatencyMs = 1000 RecoveryDropAllIPs = 120 VerifyRecoveryLock = 1 VacuumInterval = 10 VacuumMaxRunTime = 30 RepackLimit = 10000 VacuumLimit = 5000 VacuumFastPathCount = 60 MaxQueueDropMsg = 1000000 UseStatusEvents = 0 AllowUnhealthyDBRead = 0 StatHistoryInterval = 1 DeferredAttachTO = 120 AllowClientDBAttach = 1 RecoverPDBBySeqNum = 0 .fi .if n \{\ .RE .\} .RE .SS "getvar \fINAME\fR" .PP Get the runtime value of a tuneable variable\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb getvar MaxRedirectCount MaxRedirectCount = 3 .fi .if n \{\ .RE .\} .RE .SS "setvar \fINAME\fR \fIVALUE\fR" .PP Set the runtime value of a tuneable variable\&. .PP Example: ctdb setvar MaxRedirectCount 5 .SS "lvsmaster" .PP This command shows which node is currently the LVSMASTER\&. The LVSMASTER is the node in the cluster which drives the LVS system and which receives all incoming traffic from clients\&. .PP LVS is the mode where the entire CTDB/Samba cluster uses a single ip address for the entire cluster\&. In this mode all clients connect to one specific node which will then multiplex/loadbalance the clients evenly onto the other nodes in the cluster\&. This is an alternative to using public ip addresses\&. See the manpage for ctdbd for more information about LVS\&. .SS "lvs" .PP This command shows which nodes in the cluster are currently active in the LVS configuration\&. I\&.e\&. which nodes we are currently loadbalancing the single ip address across\&. .PP LVS will by default only loadbalance across those nodes that are both LVS capable and also HEALTHY\&. Except if all nodes are UNHEALTHY in which case LVS will loadbalance across all UNHEALTHY nodes as well\&. LVS will never use nodes that are DISCONNECTED, STOPPED, BANNED or DISABLED\&. .PP Example output: .sp .if n \{\ .RS 4 .\} .nf 2:10\&.0\&.0\&.13 3:10\&.0\&.0\&.14 .fi .if n \{\ .RE .\} .SS "getcapabilities" .PP This command shows the capabilities of the current node\&. See the CAPABILITIES section in \fBctdb\fR(7) for more details\&. .PP Example output: .sp .if n \{\ .RS 4 .\} .nf RECMASTER: YES LMASTER: YES LVS: NO NATGW: YES .fi .if n \{\ .RE .\} .SS "statistics" .PP Collect statistics from the CTDB daemon about how many calls it has served\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb statistics CTDB version 1 num_clients 3 frozen 0 recovering 0 client_packets_sent 360489 client_packets_recv 360466 node_packets_sent 480931 node_packets_recv 240120 keepalive_packets_sent 4 keepalive_packets_recv 3 node req_call 2 reply_call 2 req_dmaster 0 reply_dmaster 0 reply_error 0 req_message 42 req_control 120408 reply_control 360439 client req_call 2 req_message 24 req_control 360440 timeouts call 0 control 0 traverse 0 total_calls 2 pending_calls 0 lockwait_calls 0 pending_lockwait_calls 0 memory_used 5040 max_hop_count 0 max_call_latency 4\&.948321 sec max_lockwait_latency 0\&.000000 sec .fi .if n \{\ .RE .\} .RE .SS "statisticsreset" .PP This command is used to clear all statistics counters in a node\&. .PP Example: ctdb statisticsreset .SS "dbstatistics \fIDB\fR" .PP Display statistics about the database DB\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb dbstatistics locking\&.tdb DB Statistics: locking\&.tdb ro_delegations 0 ro_revokes 0 locks total 14356 failed 0 current 0 pending 0 hop_count_buckets: 28087 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 lock_buckets: 0 14188 38 76 32 19 3 0 0 0 0 0 0 0 0 0 locks_latency MIN/AVG/MAX 0\&.001066/0\&.012686/4\&.202292 sec out of 14356 Num Hot Keys: 1 Count:8 Key:ff5bd7cb3ee3822edc1f0000000000000000000000000000 .fi .if n \{\ .RE .\} .RE .SS "getreclock" .PP This command is used to show the filename of the reclock file that is used\&. .PP Example output: .sp .if n \{\ .RS 4 .\} .nf Reclock file:/gpfs/\&.ctdb/shared .fi .if n \{\ .RE .\} .SS "setreclock [filename]" .PP This command is used to modify, or clear, the file that is used as the reclock file at runtime\&. When this command is used, the reclock file checks are disabled\&. To re\-enable the checks the administrator needs to activate the "VerifyRecoveryLock" tunable using "ctdb setvar"\&. .PP If run with no parameter this will remove the reclock file completely\&. If run with a parameter the parameter specifies the new filename to use for the recovery lock\&. .PP This command only affects the runtime settings of a ctdb node and will be lost when ctdb is restarted\&. For persistent changes to the reclock file setting you must edit /etc/sysconfig/ctdb\&. .SS "getdebug" .PP Get the current debug level for the node\&. the debug level controls what information is written to the log file\&. .PP The debug levels are mapped to the corresponding syslog levels\&. When a debug level is set, only those messages at that level and higher levels will be printed\&. .PP The list of debug levels from highest to lowest are : .PP EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG .SS "setdebug \fIDEBUGLEVEL\fR" .PP Set the debug level of a node\&. This controls what information will be logged\&. .PP The debuglevel is one of EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG .SS "getpid" .PP This command will return the process id of the ctdb daemon\&. .SS "disable" .PP This command is used to administratively disable a node in the cluster\&. A disabled node will still participate in the cluster and host clustered TDB records but its public ip address has been taken over by a different node and it no longer hosts any services\&. .SS "enable" .PP Re\-enable a node that has been administratively disabled\&. .SS "stop" .PP This command is used to administratively STOP a node in the cluster\&. A STOPPED node is connected to the cluster but will not host any public ip addresse, nor does it participate in the VNNMAP\&. The difference between a DISABLED node and a STOPPED node is that a STOPPED node does not host any parts of the database which means that a recovery is required to stop/continue nodes\&. .SS "continue" .PP Re\-start a node that has been administratively stopped\&. .SS "addip \fIIPADDR\fR/\fImask\fR \fIIFACE\fR" .PP This command is used to add a new public ip to a node during runtime\&. This allows public addresses to be added to a cluster without having to restart the ctdb daemons\&. .PP Note that this only updates the runtime instance of ctdb\&. Any changes will be lost next time ctdb is restarted and the public addresses file is re\-read\&. If you want this change to be permanent you must also update the public addresses file manually\&. .SS "delip \fIIPADDR\fR" .PP This command is used to remove a public ip from a node during runtime\&. If this public ip is currently hosted by the node it being removed from, the ip will first be failed over to another node, if possible, before it is removed\&. .PP Note that this only updates the runtime instance of ctdb\&. Any changes will be lost next time ctdb is restarted and the public addresses file is re\-read\&. If you want this change to be permanent you must also update the public addresses file manually\&. .SS "moveip \fIIPADDR\fR \fIPNN\fR" .PP This command can be used to manually fail a public ip address to a specific node\&. .PP In order to manually override the "automatic" distribution of public ip addresses that ctdb normally provides, this command only works when you have changed the tunables for the daemon to: .PP DeterministicIPs = 0 .PP NoIPFailback = 1 .SS "shutdown" .PP This command will shutdown a specific CTDB daemon\&. .SS "setlmasterrole on|off" .PP This command is used ot enable/disable the LMASTER capability for a node at runtime\&. This capability determines whether or not a node can be used as an LMASTER for records in the database\&. A node that does not have the LMASTER capability will not show up in the vnnmap\&. .PP Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command\&. .PP Once this setting has been enabled/disabled, you need to perform a recovery for it to take effect\&. .PP See also "ctdb getcapabilities" .SS "setrecmasterrole on|off" .PP This command is used ot enable/disable the RECMASTER capability for a node at runtime\&. This capability determines whether or not a node can be used as an RECMASTER for the cluster\&. A node that does not have the RECMASTER capability can not win a recmaster election\&. A node that already is the recmaster for the cluster when the capability is stripped off the node will remain the recmaster until the next cluster election\&. .PP Nodes will by default have this capability, but it can be stripped off nodes by the setting in the sysconfig file or by using this command\&. .PP See also "ctdb getcapabilities" .SS "reloadnodes" .PP This command is used when adding new nodes, or removing existing nodes from an existing cluster\&. .PP Procedure to add a node: .PP 1, To expand an existing cluster, first ensure with \*(Aqctdb status\*(Aq that all nodes are up and running and that they are all healthy\&. Do not try to expand a cluster unless it is completely healthy! .PP 2, On all nodes, edit /etc/ctdb/nodes and add the new node as the last entry to the file\&. The new node MUST be added to the end of this file! .PP 3, Verify that all the nodes have identical /etc/ctdb/nodes files after you edited them and added the new node! .PP 4, Run \*(Aqctdb reloadnodes\*(Aq to force all nodes to reload the nodesfile\&. .PP 5, Use \*(Aqctdb status\*(Aq on all nodes and verify that they now show the additional node\&. .PP 6, Install and configure the new node and bring it online\&. .PP Procedure to remove a node: .PP 1, To remove a node from an existing cluster, first ensure with \*(Aqctdb status\*(Aq that all nodes, except the node to be deleted, are up and running and that they are all healthy\&. Do not try to remove a node from a cluster unless the cluster is completely healthy! .PP 2, Shutdown and poweroff the node to be removed\&. .PP 3, On all other nodes, edit the /etc/ctdb/nodes file and comment out the node to be removed\&. Do not delete the line for that node, just comment it out by adding a \*(Aq#\*(Aq at the beginning of the line\&. .PP 4, Run \*(Aqctdb reloadnodes\*(Aq to force all nodes to reload the nodesfile\&. .PP 5, Use \*(Aqctdb status\*(Aq on all nodes and verify that the deleted node no longer shows up in the list\&.\&. .PP .SS "reloadips [\fIPNN\-LIST\fR]" .PP This command reloads the public addresses configuration file on the specified nodes\&. When it completes addresses will be reconfigured and reassigned across the cluster as necessary\&. .SS "getdbmap" .PP This command lists all clustered TDB databases that the CTDB daemon has attached to\&. Some databases are flagged as PERSISTENT, this means that the database stores data persistently and the data will remain across reboots\&. One example of such a database is secrets\&.tdb where information about how the cluster was joined to the domain is stored\&. .PP If a PERSISTENT database is not in a healthy state the database is flagged as UNHEALTHY\&. If there\*(Aqs at least one completely healthy node running in the cluster, it\*(Aqs possible that the content is restored by a recovery run automaticly\&. Otherwise an administrator needs to analyze the problem\&. .PP See also "ctdb getdbstatus", "ctdb backupdb", "ctdb restoredb", "ctdb dumpbackup", "ctdb wipedb", "ctdb setvar AllowUnhealthyDBRead 1" and (if samba or tdb\-utils are installed) "tdbtool check"\&. .PP Most databases are not persistent and only store the state information that the currently running samba daemons need\&. These databases are always wiped when ctdb/samba starts and when a node is rebooted\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb getdbmap Number of databases:10 dbid:0x435d3410 name:notify\&.tdb path:/var/ctdb/notify\&.tdb\&.0 dbid:0x42fe72c5 name:locking\&.tdb path:/var/ctdb/locking\&.tdb\&.0 dbid:0x1421fb78 name:brlock\&.tdb path:/var/ctdb/brlock\&.tdb\&.0 dbid:0x17055d90 name:connections\&.tdb path:/var/ctdb/connections\&.tdb\&.0 dbid:0xc0bdde6a name:sessionid\&.tdb path:/var/ctdb/sessionid\&.tdb\&.0 dbid:0x122224da name:test\&.tdb path:/var/ctdb/test\&.tdb\&.0 dbid:0x2672a57f name:idmap2\&.tdb path:/var/ctdb/persistent/idmap2\&.tdb\&.0 PERSISTENT dbid:0xb775fff6 name:secrets\&.tdb path:/var/ctdb/persistent/secrets\&.tdb\&.0 PERSISTENT dbid:0xe98e08b6 name:group_mapping\&.tdb path:/var/ctdb/persistent/group_mapping\&.tdb\&.0 PERSISTENT dbid:0x7bbbd26c name:passdb\&.tdb path:/var/ctdb/persistent/passdb\&.tdb\&.0 PERSISTENT # ctdb getdbmap # example for unhealthy database Number of databases:1 dbid:0xb775fff6 name:secrets\&.tdb path:/var/ctdb/persistent/secrets\&.tdb\&.0 PERSISTENT UNHEALTHY # ctdb \-Y getdbmap :ID:Name:Path:Persistent:Unhealthy: :0x7bbbd26c:passdb\&.tdb:/var/ctdb/persistent/passdb\&.tdb\&.0:1:0: .fi .if n \{\ .RE .\} .RE .SS "backupdb \fIDB\fR \fIFILE\fR" .PP Copy the contents of database DB to FILE\&. FILE can later be read back using \fBrestoredb\fR\&. This is mainly useful for backing up persistent databases such as secrets\&.tdb and similar\&. .SS "restoredb \fIFILE\fR [\fIDB\fR]" .PP This command restores a persistent database that was previously backed up using backupdb\&. By default the data will be restored back into the same database as it was created from\&. By specifying dbname you can restore the data into a different database\&. .SS "getlog [\fILEVEL\fR] [recoverd]" .PP In addition to the normal logging to a log file, CTDB also keeps a in\-memory ringbuffer containing the most recent log entries for all log levels (except DEBUG)\&. .PP This is useful since it allows for keeping continuous logs to a file at a reasonable non\-verbose level, but shortly after an incident has occured, a much more detailed log can be pulled from memory\&. This can allow you to avoid having to reproduce an issue due to the on\-disk logs being of insufficient detail\&. .PP This command extracts all messages of level or lower log level from memory and prints it to the screen\&. The level is not specified it defaults to NOTICE\&. .PP By default, logs are extracted from the main CTDB daemon\&. If the recoverd option is given then logs are extracted from the recovery daemon\&. .SS "clearlog [recoverd]" .PP This command clears the in\-memory logging ringbuffer\&. .PP By default, logs are cleared in the main CTDB daemon\&. If the recoverd option is given then logs are cleared in the recovery daemon\&. .SS "setdbreadonly \fIDB\fR" .PP This command will enable the read\-only record support for a database\&. This is an experimental feature to improve performance for contended records primarily in locking\&.tdb and brlock\&.tdb\&. When enabling this feature you must set it on all nodes in the cluster\&. .SS "setdbsticky \fIDB\fR" .PP This command will enable the sticky record support for the specified database\&. This is an experimental feature to improve performance for contended records primarily in locking\&.tdb and brlock\&.tdb\&. When enabling this feature you must set it on all nodes in the cluster\&. .SH "INTERNAL COMMANDS" .PP Internal commands are used by CTDB\*(Aqs scripts and are not required for managing a CTDB cluster\&. Their parameters and behaviour are subject to change\&. .SS "gettickles \fIIPADDR\fR" .PP Show TCP connections that are registered with CTDB to be "tickled" if there is a failover\&. .SS "gratiousarp \fIIPADDR\fR \fIINTERFACE\fR" .PP Send out a gratious ARP for the specified interface through the specified interface\&. This command is mainly used by the ctdb eventscripts\&. .SS "killtcp" .PP Read a list of TCP connections, one per line, from standard input and terminate each connection\&. A connection is specified as: .sp .if n \{\ .RS 4 .\} .nf \fISRC\-IPADDR\fR:\fISRC\-PORT\fR \fIDST\-IPADDR\fR:\fIDST\-PORT\fR .fi .if n \{\ .RE .\} .PP Each connection is terminated by issuing a TCP RST to the SRC\-IPADDR:SRC\-PORT endpoint\&. .PP A single connection can be specified on the command\-line rather than on standard input\&. .SS "pdelete \fIDB\fR \fIKEY\fR" .PP Delete KEY from DB\&. .SS "pfetch \fIDB\fR \fIKEY\fR" .PP Print the value associated with KEY in DB\&. .SS "pstore \fIDB\fR \fIKEY\fR \fIFILE\fR" .PP Store KEY in DB with contents of FILE as the associated value\&. .SS "ptrans \fIDB\fR [\fIFILE\fR]" .PP Read a list of key\-value pairs, one per line from FILE, and store them in DB using a single transaction\&. An empty value is equivalent to deleting the given key\&. .PP The key and value should be separated by spaces or tabs\&. Each key/value should be a printable string enclosed in double\-quotes\&. .SS "runstate [setup|first_recovery|startup|running]" .PP Print the runstate of the specified node\&. Runstates are used to serialise important state transitions in CTDB, particularly during startup\&. .PP If one or more optional runstate arguments are specified then the node must be in one of these runstates for the command to succeed\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb runstate RUNNING .fi .if n \{\ .RE .\} .RE .SS "setifacelink \fIIFACE\fR up|down" .PP Set the internal state of network interface IFACE\&. This is typically used in the 10\&.interface script in the "monitor" event\&. .PP Example: ctdb setifacelink eth0 up .SS "setnatgwstate on|off" .PP Enable or disable the NAT gateway master capability on a node\&. .SS "tickle \fISRC\-IPADDR\fR:\fISRC\-PORT\fR \fIDST\-IPADDR\fR:\fIDST\-PORT\fR" .PP Send a TCP tickle to the source host for the specified TCP connection\&. A TCP tickle is a TCP ACK packet with an invalid sequence and acknowledge number and will when received by the source host result in it sending an immediate correct ACK back to the other end\&. .PP TCP tickles are useful to "tickle" clients after a IP failover has occured since this will make the client immediately recognize the TCP connection has been disrupted and that the client will need to reestablish\&. This greatly speeds up the time it takes for a client to detect and reestablish after an IP failover in the ctdb cluster\&. .SS "version" .PP Display the CTDB version\&. .SH "DEBUGGING COMMANDS" .PP These commands are primarily used for CTDB development and testing and should not be used for normal administration\&. .SS "OPTIONS" .PP \-\-print\-emptyrecords .RS 4 This enables printing of empty records when dumping databases with the catdb, cattbd and dumpdbbackup commands\&. Records with empty data segment are considered deleted by ctdb and cleaned by the vacuuming mechanism, so this switch can come in handy for debugging the vacuuming behaviour\&. .RE .PP \-\-print\-datasize .RS 4 This lets database dumps (catdb, cattdb, dumpdbbackup) print the size of the record data instead of dumping the data contents\&. .RE .PP \-\-print\-lmaster .RS 4 This lets catdb print the lmaster for each record\&. .RE .PP \-\-print\-hash .RS 4 This lets database dumps (catdb, cattdb, dumpdbbackup) print the hash for each record\&. .RE .PP \-\-print\-recordflags .RS 4 This lets catdb and dumpdbbackup print the record flags for each record\&. Note that cattdb always prints the flags\&. .RE .SS "process\-exists \fIPID\fR" .PP This command checks if a specific process exists on the CTDB host\&. This is mainly used by Samba to check if remote instances of samba are still running or not\&. .SS "getdbstatus \fIDB\fR" .PP This command displays more details about a database\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb getdbstatus test\&.tdb\&.0 dbid: 0x122224da name: test\&.tdb path: /var/ctdb/test\&.tdb\&.0 PERSISTENT: no HEALTH: OK # ctdb getdbstatus registry\&.tdb # with a corrupted TDB dbid: 0xf2a58948 name: registry\&.tdb path: /var/ctdb/persistent/registry\&.tdb\&.0 PERSISTENT: yes HEALTH: NO\-HEALTHY\-NODES \- ERROR \- Backup of corrupted TDB in \*(Aq/var/ctdb/persistent/registry\&.tdb\&.0\&.corrupted\&.20091208091949\&.0Z\*(Aq .fi .if n \{\ .RE .\} .RE .SS "catdb \fIDB\fR" .PP Print a dump of the clustered TDB database DB\&. .SS "cattdb \fIDB\fR" .PP Print a dump of the contents of the local TDB database DB\&. .SS "dumpdbbackup \fIFILE\fR" .PP Print a dump of the contents from database backup FILE, similar to \fBcatdb\fR\&. .SS "wipedb \fIDB\fR" .PP Remove all contents of database DB\&. .SS "recover" .PP This command will trigger the recovery daemon to do a cluster recovery\&. .SS "ipreallocate, sync" .PP This command will force the recovery master to perform a full ip reallocation process and redistribute all ip addresses\&. This is useful to "reset" the allocations back to its default state if they have been changed using the "moveip" command\&. While a "recover" will also perform this reallocation, a recovery is much more hevyweight since it will also rebuild all the databases\&. .SS "getmonmode" .PP This command returns the monutoring mode of a node\&. The monitoring mode is either ACTIVE or DISABLED\&. Normally a node will continuously monitor that all other nodes that are expected are in fact connected and that they respond to commands\&. .PP ACTIVE \- This is the normal mode\&. The node is actively monitoring all other nodes, both that the transport is connected and also that the node responds to commands\&. If a node becomes unavailable, it will be marked as DISCONNECTED and a recovery is initiated to restore the cluster\&. .PP DISABLED \- This node is not monitoring that other nodes are available\&. In this mode a node failure will not be detected and no recovery will be performed\&. This mode is useful when for debugging purposes one wants to attach GDB to a ctdb process but wants to prevent the rest of the cluster from marking this node as DISCONNECTED and do a recovery\&. .SS "setmonmode 0|1" .PP This command can be used to explicitly disable/enable monitoring mode on a node\&. The main purpose is if one wants to attach GDB to a running ctdb daemon but wants to prevent the other nodes from marking it as DISCONNECTED and issuing a recovery\&. To do this, set monitoring mode to 0 on all nodes before attaching with GDB\&. Remember to set monitoring mode back to 1 afterwards\&. .SS "attach \fIDBNAME\fR [persistent]" .PP This is a debugging command\&. This command will make the CTDB daemon create a new CTDB database and attach to it\&. .SS "dumpmemory" .PP This is a debugging command\&. This command will make the ctdb daemon to write a fill memory allocation map to standard output\&. .SS "rddumpmemory" .PP This is a debugging command\&. This command will dump the talloc memory allocation tree for the recovery daemon to standard output\&. .SS "thaw" .PP Thaw a previously frozen node\&. .SS "eventscript \fIARGUMENTS\fR" .PP This is a debugging command\&. This command can be used to manually invoke and run the eventscritps with arbitrary arguments\&. .SS "ban \fIBANTIME\fR" .PP Administratively ban a node for BANTIME seconds\&. The node will be unbanned after BANTIME seconds have elapsed\&. .PP A banned node does not participate in the cluster\&. It does not host any records for the clustered TDB and does not host any public IP addresses\&. .PP Nodes are automatically banned if they misbehave\&. For example, a node may be banned if it causes too many cluster recoveries\&. .PP To administratively exclude a node from a cluster use the \fBstop\fR command\&. .SS "unban" .PP This command is used to unban a node that has either been administratively banned using the ban command or has been automatically banned\&. .SS "rebalancenode [\fIPNN\-LIST\fR]" .PP This command marks the given nodes as rebalance targets in the LCP2 IP allocation algorithm\&. The \fBreloadips\fR command will do this as necessary so this command should not be needed\&. .SS "check_srvids \fISRVID\fR \&.\&.\&." .PP This command checks whether a set of srvid message ports are registered on the node or not\&. The command takes a list of values to check\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBExample\fR .RS 4 .sp .if n \{\ .RS 4 .\} .nf # ctdb check_srvids 1 2 3 14765 Server id 0:1 does not exist Server id 0:2 does not exist Server id 0:3 does not exist Server id 0:14765 exists .fi .if n \{\ .RE .\} .RE .SS "vacuum [\fImax\-records\fR]" .PP Over time CTDB databases will fill up with empty deleted records which will lead to a progressive slow down of CTDB database access\&. This command is used to prune all databases and delete all empty records from the cluster\&. .PP By default, vacuum will delete all empty records from all databases\&. If [max_records] is specified, the command will only delete the first [max_records] empty records for each database\&. .PP Vacuum only deletes records where the local node is the lmaster\&. To delete all records from the entire cluster you need to run a vacuum from each node\&. This command is not disruptive\&. Samba is unaffected and will still be able to read/write records normally while the database is being vacuumed\&. .PP Example: ctdb vacuum .PP By default, this operation is issued from the 00\&.ctdb event script every 5 minutes\&. .SS "repack [max_freelist]" .PP Over time, when records are created and deleted in a TDB, the TDB list of free space will become fragmented\&. This can lead to a slowdown in accessing TDB records\&. This command is used to defragment a TDB database and pruning the freelist\&. .PP If [max_freelist] is specified, then a database will only be repacked if it has more than this number of entries in the freelist\&. .PP During repacking of the database, the entire TDB database will be locked to prevent writes\&. If samba tries to write to a record in the database during a repack operation, samba will block until the repacking has completed\&. .PP This command can be disruptive and can cause samba to block for the duration of the repack operation\&. In general, a repack operation will take less than one second to complete\&. .PP A repack operation will only defragment the local TDB copy of the CTDB database\&. You need to run this command on all of the nodes to repack a CTDB database completely\&. .PP Example: ctdb repack 1000 .PP By default, this operation is issued from the 00\&.ctdb event script every 5 minutes\&. .SH "SEE ALSO" .PP \fBctdbd\fR(1), \fBonnode\fR(1), \fBctdb\fR(7), \fBctdb-tunables\fR(7), \m[blue]\fB\%http://ctdb.samba.org/\fR\m[] .SH "AUTHOR" .br .PP This documentation was written by Ronnie Sahlberg, Amitay Isaacs, Martin Schwenke .SH "COPYRIGHT" .br Copyright \(co 2007 Andrew Tridgell, Ronnie Sahlberg .br .PP This program 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 3 of the License, or (at your option) any later version\&. .PP This program 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\&. .PP You should have received a copy of the GNU General Public License along with this program; if not, see \m[blue]\fB\%http://www.gnu.org/licenses\fR\m[]\&. .sp ctdb-2.5.1.dfsg/doc/ctdbd_wrapper.1.xml0000644000175000017500000000573512245023514017505 0ustar mathieumathieu ctdbd_wrapper 1 ctdb CTDB - clustered TDB database ctdbd_wrapper Wrapper for ctdbd ctdbd_wrapper PIDFILE start stop DESCRIPTION ctdbd_wrapper is used to start or stop the main CTDB daemon. PIDFILE specifies the location of the file containing the PID of the main CTDB daemon. ctdbd_wrapper constructs command-line options for ctdbd from configuration variables specified in ctdbd.conf 5. See ctdb 7 for an overview of CTDB. SEE ALSO ctdbd 1, ctdbd.conf 5, ctdb 7, This documentation was written by Amitay Isaacs, Martin Schwenke 2007 Andrew Tridgell Ronnie Sahlberg This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb-2.5.1.dfsg/doc/ltdbtool.1.html0000644000175000017500000001243512245332461016653 0ustar mathieumathieultdbtool

Name

ltdbtool — manipulate CTDB's local TDB files

Synopsis

ltdbtool [OPTION...] {COMMAND} [COMMAND-ARGS]

DESCRIPTION

ltdbtool is a utility to manipulate CTDB's local TDB databases (LTDBs) without connecting to a CTDB daemon.

It can be used to:

  • dump the contents of a LTDB, optionally printing the CTDB record header information,

  • convert between an LTDB and a non-clustered tdb by adding or removing CTDB headers and

  • convert between 64 and 32 bit LTDBs where the CTDB record headers differ by 4 bytes of padding.

OPTIONS

-e

Dump empty records. These are normally excluded.

-p

Dump with header information, similar to "ctdb catdb".

-s { 0 | 32 | 64 }

Specify how to determine the CTDB record header size for the input database:

0

no CTDB header

32

CTDB header size of a 32 bit system (20 bytes)

64

CTDB header size of a 64 bit system (24 bytes)

The default is 32 or 64 depending on the system architecture.

-o { 0 | 32 | 64 }

Specify how to determine the CTDB record header size for the output database, see -s.

-S SIZE

Explicitly specify the CTDB record header SIZE of the input database in bytes.

-O SIZE

Explicitly specify the CTDB record header SIZE for the output database in bytes.

-h

Print help text.

COMMANDS

help

Print help text.

dump IDB

Dump the contents of an LTDB input file IDB to standard output in a human-readable format.

convert IDB ODB

Copy an LTDB input file IDB to output file ODB, optionally adding or removing CTDB headers.

EXAMPLES

Print a local tdb in "tdbdump" style:

      ltdbtool dump idmap2.tdb.0
    

Print a local tdb with header information similar to "ctdb catdb":

      ltdbtool dump -p idmap2.tdb.0
    

Strip the CTDB headers from records:

      ltdbtool convert -o0 idmap2.tdb.0 idmap.tdb
    

Strip 64 bit CTDB headers from records, running on i386:

      ltdbtool convert -s64 -o0 idmap2.tdb.0 idmap.tdb
    

Strip the CTDB headers from records by piping through tdbrestore:

      ltdbtool dump idmap2.tdb.0 | tdbrestore idmap.tdb
    

Convert a local tdb from a 64 bit system for usage on a 32 bit system:

      ltdbtool convert -s64 -o32 idmap2.tdb.0 idmap2.tdb.1
    

Add a default header:

      ltdbtool convert -s0 idmap.tdb idmap2.tdb.0
    

SEE ALSO

ctdb(1), tdbdump(1), tdbrestore(1), ctdb(7), http://ctdb.samba.org/

ctdb-2.5.1.dfsg/doc/ping_pong.1.xml0000644000175000017500000000755712245023514016651 0ustar mathieumathieu ping_pong 1 ctdb CTDB - clustered TDB database ping_pong measures the ping-pong byte range lock latency ping_pong -r -w -rw -m -c FILENAME NUM-LOCKS DESCRIPTION ping_pong measures the byte range lock latency. It is especially useful on a cluster of nodes sharing a common lock manager as it will give some indication of the lock manager's performance under stress. FILENAME is a file on shared storage to use for byte range locking tests. NUM-LOCKS is the number of byte range locks, so needs to be (strictly) greater than the number of nodes in the cluster. OPTIONS -r test read performance -w test write performance -m use mmap -c validate the locks EXAMPLES Testing lock coherence ping_pong test.dat N Testing lock coherence with lock validation ping_pong -c test.dat N Testing IO coherence ping_pong -rw test.dat N SEE ALSO ctdb 7, This documentation was written by Mathieu Parent 2002 Andrew Tridgell This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . ctdb-2.5.1.dfsg/lib/0000755000175000017500000000000012254276664014013 5ustar mathieumathieuctdb-2.5.1.dfsg/lib/socket_wrapper/0000755000175000017500000000000012245023514017023 5ustar mathieumathieuctdb-2.5.1.dfsg/lib/socket_wrapper/socket_wrapper.c0000644000175000017500000016110312245023514022221 0ustar mathieumathieu/* * Copyright (C) Jelmer Vernooij 2005,2008 * Copyright (C) Stefan Metzmacher 2006-2009 * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* Socket wrapper library. Passes all socket communication over unix domain sockets if the environment variable SOCKET_WRAPPER_DIR is set. */ #include "config.h" #ifdef HAVE_LIBREPLACE #define SOCKET_WRAPPER_NOT_REPLACE #include "replace.h" #include "system/network.h" #include "system/filesys.h" #include "system/time.h" #else /* HAVE_LIBREPLACE */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /* HAVE_LIBREPLACE */ #ifndef _PUBLIC_ #define _PUBLIC_ #endif #define SWRAP_DLIST_ADD(list,item) do { \ if (!(list)) { \ (item)->prev = NULL; \ (item)->next = NULL; \ (list) = (item); \ } else { \ (item)->prev = NULL; \ (item)->next = (list); \ (list)->prev = (item); \ (list) = (item); \ } \ } while (0) #define SWRAP_DLIST_REMOVE(list,item) do { \ if ((list) == (item)) { \ (list) = (item)->next; \ if (list) { \ (list)->prev = NULL; \ } \ } else { \ if ((item)->prev) { \ (item)->prev->next = (item)->next; \ } \ if ((item)->next) { \ (item)->next->prev = (item)->prev; \ } \ } \ (item)->prev = NULL; \ (item)->next = NULL; \ } while (0) /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support * for now */ #define REWRITE_CALLS #ifdef REWRITE_CALLS #define real_accept accept #define real_connect connect #define real_bind bind #define real_listen listen #define real_getpeername getpeername #define real_getsockname getsockname #define real_getsockopt getsockopt #define real_setsockopt setsockopt #define real_recvfrom recvfrom #define real_sendto sendto #define real_sendmsg sendmsg #define real_ioctl ioctl #define real_recv recv #define real_read read #define real_send send #define real_readv readv #define real_writev writev #define real_socket socket #define real_close close #define real_dup dup #define real_dup2 dup2 #endif #ifdef HAVE_GETTIMEOFDAY_TZ #define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL) #else #define swrapGetTimeOfDay(tval) gettimeofday(tval) #endif /* we need to use a very terse format here as IRIX 6.4 silently truncates names to 16 chars, so if we use a longer name then we can't tell which port a packet came from with recvfrom() with this format we have 8 chars left for the directory name */ #define SOCKET_FORMAT "%c%02X%04X" #define SOCKET_TYPE_CHAR_TCP 'T' #define SOCKET_TYPE_CHAR_UDP 'U' #define SOCKET_TYPE_CHAR_TCP_V6 'X' #define SOCKET_TYPE_CHAR_UDP_V6 'Y' /* This limit is to avoid broadcast sendto() needing to stat too many * files. It may be raised (with a performance cost) to up to 254 * without changing the format above */ #define MAX_WRAPPED_INTERFACES 32 #ifdef HAVE_IPV6 /* * FD00::5357:5FXX */ static const struct in6_addr *swrap_ipv6(void) { static struct in6_addr v; static int initialized; int ret; if (initialized) { return &v; } initialized = 1; ret = inet_pton(AF_INET6, "FD00::5357:5F00", &v); if (ret <= 0) { abort(); } return &v; } #endif static struct sockaddr *sockaddr_dup(const void *data, socklen_t len) { struct sockaddr *ret = (struct sockaddr *)malloc(len); memcpy(ret, data, len); return ret; } static void set_port(int family, int prt, struct sockaddr *addr) { switch (family) { case AF_INET: ((struct sockaddr_in *)addr)->sin_port = htons(prt); break; #ifdef HAVE_IPV6 case AF_INET6: ((struct sockaddr_in6 *)addr)->sin6_port = htons(prt); break; #endif } } static size_t socket_length(int family) { switch (family) { case AF_INET: return sizeof(struct sockaddr_in); #ifdef HAVE_IPV6 case AF_INET6: return sizeof(struct sockaddr_in6); #endif } return 0; } struct socket_info_fd { struct socket_info_fd *prev, *next; int fd; }; struct socket_info { struct socket_info_fd *fds; int family; int type; int protocol; int bound; int bcast; int is_server; int connected; int defer_connect; char *tmp_path; struct sockaddr *myname; socklen_t myname_len; struct sockaddr *peername; socklen_t peername_len; struct { unsigned long pck_snd; unsigned long pck_rcv; } io; struct socket_info *prev, *next; }; static struct socket_info *sockets; const char *socket_wrapper_dir(void) { const char *s = getenv("SOCKET_WRAPPER_DIR"); if (s == NULL) { return NULL; } if (strncmp(s, "./", 2) == 0) { s += 2; } return s; } unsigned int socket_wrapper_default_iface(void) { const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE"); if (s) { unsigned int iface; if (sscanf(s, "%u", &iface) == 1) { if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) { return iface; } } } return 1;/* 127.0.0.1 */ } static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len) { unsigned int iface; unsigned int prt; const char *p; char type; p = strrchr(un->sun_path, '/'); if (p) p++; else p = un->sun_path; if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) { errno = EINVAL; return -1; } if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) { errno = EINVAL; return -1; } if (prt > 0xFFFF) { errno = EINVAL; return -1; } switch(type) { case SOCKET_TYPE_CHAR_TCP: case SOCKET_TYPE_CHAR_UDP: { struct sockaddr_in *in2 = (struct sockaddr_in *)(void *)in; if ((*len) < sizeof(*in2)) { errno = EINVAL; return -1; } memset(in2, 0, sizeof(*in2)); in2->sin_family = AF_INET; in2->sin_addr.s_addr = htonl((127<<24) | iface); in2->sin_port = htons(prt); *len = sizeof(*in2); break; } #ifdef HAVE_IPV6 case SOCKET_TYPE_CHAR_TCP_V6: case SOCKET_TYPE_CHAR_UDP_V6: { struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)(void *)in; if ((*len) < sizeof(*in2)) { errno = EINVAL; return -1; } memset(in2, 0, sizeof(*in2)); in2->sin6_family = AF_INET6; in2->sin6_addr = *swrap_ipv6(); in2->sin6_addr.s6_addr[15] = iface; in2->sin6_port = htons(prt); *len = sizeof(*in2); break; } #endif default: errno = EINVAL; return -1; } return 0; } static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un, int *bcast) { char type = '\0'; unsigned int prt; unsigned int iface; int is_bcast = 0; if (bcast) *bcast = 0; switch (inaddr->sa_family) { case AF_INET: { const struct sockaddr_in *in = (const struct sockaddr_in *)(const void *)inaddr; unsigned int addr = ntohl(in->sin_addr.s_addr); char u_type = '\0'; char b_type = '\0'; char a_type = '\0'; switch (si->type) { case SOCK_STREAM: u_type = SOCKET_TYPE_CHAR_TCP; break; case SOCK_DGRAM: u_type = SOCKET_TYPE_CHAR_UDP; a_type = SOCKET_TYPE_CHAR_UDP; b_type = SOCKET_TYPE_CHAR_UDP; break; } prt = ntohs(in->sin_port); if (a_type && addr == 0xFFFFFFFF) { /* 255.255.255.255 only udp */ is_bcast = 2; type = a_type; iface = socket_wrapper_default_iface(); } else if (b_type && addr == 0x7FFFFFFF) { /* 127.255.255.255 only udp */ is_bcast = 1; type = b_type; iface = socket_wrapper_default_iface(); } else if ((addr & 0xFFFFFF00) == 0x7F000000) { /* 127.0.0.X */ is_bcast = 0; type = u_type; iface = (addr & 0x000000FF); } else { errno = ENETUNREACH; return -1; } if (bcast) *bcast = is_bcast; break; } #ifdef HAVE_IPV6 case AF_INET6: { const struct sockaddr_in6 *in = (const struct sockaddr_in6 *)(const void *)inaddr; struct in6_addr cmp1, cmp2; switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP_V6; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP_V6; break; } /* XXX no multicast/broadcast */ prt = ntohs(in->sin6_port); cmp1 = *swrap_ipv6(); cmp2 = in->sin6_addr; cmp2.s6_addr[15] = 0; if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) { iface = in->sin6_addr.s6_addr[15]; } else { errno = ENETUNREACH; return -1; } break; } #endif default: errno = ENETUNREACH; return -1; } if (prt == 0) { errno = EINVAL; return -1; } if (is_bcast) { snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", socket_wrapper_dir()); /* the caller need to do more processing */ return 0; } snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); return 0; } static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un, int *bcast) { char type = '\0'; unsigned int prt; unsigned int iface; struct stat st; int is_bcast = 0; if (bcast) *bcast = 0; switch (si->family) { case AF_INET: { const struct sockaddr_in *in = (const struct sockaddr_in *)(const void *)inaddr; unsigned int addr = ntohl(in->sin_addr.s_addr); char u_type = '\0'; char d_type = '\0'; char b_type = '\0'; char a_type = '\0'; prt = ntohs(in->sin_port); switch (si->type) { case SOCK_STREAM: u_type = SOCKET_TYPE_CHAR_TCP; d_type = SOCKET_TYPE_CHAR_TCP; break; case SOCK_DGRAM: u_type = SOCKET_TYPE_CHAR_UDP; d_type = SOCKET_TYPE_CHAR_UDP; a_type = SOCKET_TYPE_CHAR_UDP; b_type = SOCKET_TYPE_CHAR_UDP; break; } if (addr == 0) { /* 0.0.0.0 */ is_bcast = 0; type = d_type; iface = socket_wrapper_default_iface(); } else if (a_type && addr == 0xFFFFFFFF) { /* 255.255.255.255 only udp */ is_bcast = 2; type = a_type; iface = socket_wrapper_default_iface(); } else if (b_type && addr == 0x7FFFFFFF) { /* 127.255.255.255 only udp */ is_bcast = 1; type = b_type; iface = socket_wrapper_default_iface(); } else if ((addr & 0xFFFFFF00) == 0x7F000000) { /* 127.0.0.X */ is_bcast = 0; type = u_type; iface = (addr & 0x000000FF); } else { errno = EADDRNOTAVAIL; return -1; } break; } #ifdef HAVE_IPV6 case AF_INET6: { const struct sockaddr_in6 *in = (const struct sockaddr_in6 *)(const void *)inaddr; struct in6_addr cmp1, cmp2; switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP_V6; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP_V6; break; } /* XXX no multicast/broadcast */ prt = ntohs(in->sin6_port); cmp1 = *swrap_ipv6(); cmp2 = in->sin6_addr; cmp2.s6_addr[15] = 0; if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) { iface = socket_wrapper_default_iface(); } else if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) { iface = in->sin6_addr.s6_addr[15]; } else { errno = EADDRNOTAVAIL; return -1; } break; } #endif default: errno = EADDRNOTAVAIL; return -1; } if (bcast) *bcast = is_bcast; if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) { errno = EINVAL; return -1; } if (prt == 0) { /* handle auto-allocation of ephemeral ports */ for (prt = 5001; prt < 10000; prt++) { snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); if (stat(un->sun_path, &st) == 0) continue; set_port(si->family, prt, si->myname); break; } if (prt == 10000) { errno = ENFILE; return -1; } } snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); return 0; } static struct socket_info *find_socket_info(int fd) { struct socket_info *i; for (i = sockets; i; i = i->next) { struct socket_info_fd *f; for (f = i->fds; f; f = f->next) { if (f->fd == fd) { return i; } } } return NULL; } static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len, struct sockaddr_un *out_addr, int alloc_sock, int *bcast) { struct sockaddr *out = (struct sockaddr *)(void *)out_addr; if (!out_addr) return 0; out->sa_family = AF_UNIX; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN out->sa_len = sizeof(*out_addr); #endif switch (in_addr->sa_family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif switch (si->type) { case SOCK_STREAM: case SOCK_DGRAM: break; default: errno = ESOCKTNOSUPPORT; return -1; } if (alloc_sock) { return convert_in_un_alloc(si, in_addr, out_addr, bcast); } else { return convert_in_un_remote(si, in_addr, out_addr, bcast); } default: break; } errno = EAFNOSUPPORT; return -1; } static int sockaddr_convert_from_un(const struct socket_info *si, const struct sockaddr_un *in_addr, socklen_t un_addrlen, int family, struct sockaddr *out_addr, socklen_t *out_addrlen) { int ret; if (out_addr == NULL || out_addrlen == NULL) return 0; if (un_addrlen == 0) { *out_addrlen = 0; return 0; } switch (family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif switch (si->type) { case SOCK_STREAM: case SOCK_DGRAM: break; default: errno = ESOCKTNOSUPPORT; return -1; } ret = convert_un_in(in_addr, out_addr, out_addrlen); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN out_addr->sa_len = *out_addrlen; #endif return ret; default: break; } errno = EAFNOSUPPORT; return -1; } enum swrap_packet_type { SWRAP_CONNECT_SEND, SWRAP_CONNECT_UNREACH, SWRAP_CONNECT_RECV, SWRAP_CONNECT_ACK, SWRAP_ACCEPT_SEND, SWRAP_ACCEPT_RECV, SWRAP_ACCEPT_ACK, SWRAP_RECVFROM, SWRAP_SENDTO, SWRAP_SENDTO_UNREACH, SWRAP_PENDING_RST, SWRAP_RECV, SWRAP_RECV_RST, SWRAP_SEND, SWRAP_SEND_RST, SWRAP_CLOSE_SEND, SWRAP_CLOSE_RECV, SWRAP_CLOSE_ACK, }; struct swrap_file_hdr { uint32_t magic; uint16_t version_major; uint16_t version_minor; int32_t timezone; uint32_t sigfigs; uint32_t frame_max_len; #define SWRAP_FRAME_LENGTH_MAX 0xFFFF uint32_t link_type; }; #define SWRAP_FILE_HDR_SIZE 24 struct swrap_packet_frame { uint32_t seconds; uint32_t micro_seconds; uint32_t recorded_length; uint32_t full_length; }; #define SWRAP_PACKET_FRAME_SIZE 16 union swrap_packet_ip { struct { uint8_t ver_hdrlen; uint8_t tos; uint16_t packet_length; uint16_t identification; uint8_t flags; uint8_t fragment; uint8_t ttl; uint8_t protocol; uint16_t hdr_checksum; uint32_t src_addr; uint32_t dest_addr; } v4; #define SWRAP_PACKET_IP_V4_SIZE 20 struct { uint8_t ver_prio; uint8_t flow_label_high; uint16_t flow_label_low; uint16_t payload_length; uint8_t next_header; uint8_t hop_limit; uint8_t src_addr[16]; uint8_t dest_addr[16]; } v6; #define SWRAP_PACKET_IP_V6_SIZE 40 }; #define SWRAP_PACKET_IP_SIZE 40 union swrap_packet_payload { struct { uint16_t source_port; uint16_t dest_port; uint32_t seq_num; uint32_t ack_num; uint8_t hdr_length; uint8_t control; uint16_t window; uint16_t checksum; uint16_t urg; } tcp; #define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20 struct { uint16_t source_port; uint16_t dest_port; uint16_t length; uint16_t checksum; } udp; #define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8 struct { uint8_t type; uint8_t code; uint16_t checksum; uint32_t unused; } icmp4; #define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8 struct { uint8_t type; uint8_t code; uint16_t checksum; uint32_t unused; } icmp6; #define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8 }; #define SWRAP_PACKET_PAYLOAD_SIZE 20 #define SWRAP_PACKET_MIN_ALLOC \ (SWRAP_PACKET_FRAME_SIZE + \ SWRAP_PACKET_IP_SIZE + \ SWRAP_PACKET_PAYLOAD_SIZE) static const char *socket_wrapper_pcap_file(void) { static int initialized = 0; static const char *s = NULL; static const struct swrap_file_hdr h; static const struct swrap_packet_frame f; static const union swrap_packet_ip i; static const union swrap_packet_payload p; if (initialized == 1) { return s; } initialized = 1; /* * TODO: don't use the structs use plain buffer offsets * and PUSH_U8(), PUSH_U16() and PUSH_U32() * * for now make sure we disable PCAP support * if the struct has alignment! */ if (sizeof(h) != SWRAP_FILE_HDR_SIZE) { return NULL; } if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) { return NULL; } if (sizeof(i) != SWRAP_PACKET_IP_SIZE) { return NULL; } if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) { return NULL; } if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) { return NULL; } if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) { return NULL; } if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) { return NULL; } if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) { return NULL; } if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) { return NULL; } if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) { return NULL; } s = getenv("SOCKET_WRAPPER_PCAP_FILE"); if (s == NULL) { return NULL; } if (strncmp(s, "./", 2) == 0) { s += 2; } return s; } static uint8_t *swrap_packet_init(struct timeval *tval, const struct sockaddr *src, const struct sockaddr *dest, int socket_type, const uint8_t *payload, size_t payload_len, unsigned long tcp_seqno, unsigned long tcp_ack, unsigned char tcp_ctl, int unreachable, size_t *_packet_len) { uint8_t *base; uint8_t *buf; struct swrap_packet_frame *frame; union swrap_packet_ip *ip; union swrap_packet_payload *pay; size_t packet_len; size_t alloc_len; size_t nonwire_len = sizeof(*frame); size_t wire_hdr_len = 0; size_t wire_len = 0; size_t ip_hdr_len = 0; size_t icmp_hdr_len = 0; size_t icmp_truncate_len = 0; uint8_t protocol = 0, icmp_protocol = 0; const struct sockaddr_in *src_in = NULL; const struct sockaddr_in *dest_in = NULL; #ifdef HAVE_IPV6 const struct sockaddr_in6 *src_in6 = NULL; const struct sockaddr_in6 *dest_in6 = NULL; #endif uint16_t src_port; uint16_t dest_port; switch (src->sa_family) { case AF_INET: src_in = (const struct sockaddr_in *)src; dest_in = (const struct sockaddr_in *)dest; src_port = src_in->sin_port; dest_port = dest_in->sin_port; ip_hdr_len = sizeof(ip->v4); break; #ifdef HAVE_IPV6 case AF_INET6: src_in6 = (const struct sockaddr_in6 *)src; dest_in6 = (const struct sockaddr_in6 *)dest; src_port = src_in6->sin6_port; dest_port = dest_in6->sin6_port; ip_hdr_len = sizeof(ip->v6); break; #endif default: return NULL; } switch (socket_type) { case SOCK_STREAM: protocol = 0x06; /* TCP */ wire_hdr_len = ip_hdr_len + sizeof(pay->tcp); wire_len = wire_hdr_len + payload_len; break; case SOCK_DGRAM: protocol = 0x11; /* UDP */ wire_hdr_len = ip_hdr_len + sizeof(pay->udp); wire_len = wire_hdr_len + payload_len; break; default: return NULL; } if (unreachable) { icmp_protocol = protocol; switch (src->sa_family) { case AF_INET: protocol = 0x01; /* ICMPv4 */ icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4); break; #ifdef HAVE_IPV6 case AF_INET6: protocol = 0x3A; /* ICMPv6 */ icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6); break; #endif } if (wire_len > 64 ) { icmp_truncate_len = wire_len - 64; } wire_hdr_len += icmp_hdr_len; wire_len += icmp_hdr_len; } packet_len = nonwire_len + wire_len; alloc_len = packet_len; if (alloc_len < SWRAP_PACKET_MIN_ALLOC) { alloc_len = SWRAP_PACKET_MIN_ALLOC; } base = (uint8_t *)malloc(alloc_len); if (!base) return NULL; buf = base; frame = (struct swrap_packet_frame *)buf; frame->seconds = tval->tv_sec; frame->micro_seconds = tval->tv_usec; frame->recorded_length = wire_len - icmp_truncate_len; frame->full_length = wire_len - icmp_truncate_len; buf += SWRAP_PACKET_FRAME_SIZE; ip = (union swrap_packet_ip *)buf; switch (src->sa_family) { case AF_INET: ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */ ip->v4.tos = 0x00; ip->v4.packet_length = htons(wire_len - icmp_truncate_len); ip->v4.identification = htons(0xFFFF); ip->v4.flags = 0x40; /* BIT 1 set - means don't fraqment */ ip->v4.fragment = htons(0x0000); ip->v4.ttl = 0xFF; ip->v4.protocol = protocol; ip->v4.hdr_checksum = htons(0x0000); ip->v4.src_addr = src_in->sin_addr.s_addr; ip->v4.dest_addr = dest_in->sin_addr.s_addr; buf += SWRAP_PACKET_IP_V4_SIZE; break; #ifdef HAVE_IPV6 case AF_INET6: ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */ ip->v6.flow_label_high = 0x00; ip->v6.flow_label_low = 0x0000; ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */ ip->v6.next_header = protocol; memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16); memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16); buf += SWRAP_PACKET_IP_V6_SIZE; break; #endif } if (unreachable) { pay = (union swrap_packet_payload *)buf; switch (src->sa_family) { case AF_INET: pay->icmp4.type = 0x03; /* destination unreachable */ pay->icmp4.code = 0x01; /* host unreachable */ pay->icmp4.checksum = htons(0x0000); pay->icmp4.unused = htonl(0x00000000); buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE; /* set the ip header in the ICMP payload */ ip = (union swrap_packet_ip *)buf; ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */ ip->v4.tos = 0x00; ip->v4.packet_length = htons(wire_len - icmp_hdr_len); ip->v4.identification = htons(0xFFFF); ip->v4.flags = 0x40; /* BIT 1 set - means don't fraqment */ ip->v4.fragment = htons(0x0000); ip->v4.ttl = 0xFF; ip->v4.protocol = icmp_protocol; ip->v4.hdr_checksum = htons(0x0000); ip->v4.src_addr = dest_in->sin_addr.s_addr; ip->v4.dest_addr = src_in->sin_addr.s_addr; buf += SWRAP_PACKET_IP_V4_SIZE; src_port = dest_in->sin_port; dest_port = src_in->sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: pay->icmp6.type = 0x01; /* destination unreachable */ pay->icmp6.code = 0x03; /* address unreachable */ pay->icmp6.checksum = htons(0x0000); pay->icmp6.unused = htonl(0x00000000); buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE; /* set the ip header in the ICMP payload */ ip = (union swrap_packet_ip *)buf; ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */ ip->v6.flow_label_high = 0x00; ip->v6.flow_label_low = 0x0000; ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */ ip->v6.next_header = protocol; memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16); memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16); buf += SWRAP_PACKET_IP_V6_SIZE; src_port = dest_in6->sin6_port; dest_port = src_in6->sin6_port; break; #endif } } pay = (union swrap_packet_payload *)buf; switch (socket_type) { case SOCK_STREAM: pay->tcp.source_port = src_port; pay->tcp.dest_port = dest_port; pay->tcp.seq_num = htonl(tcp_seqno); pay->tcp.ack_num = htonl(tcp_ack); pay->tcp.hdr_length = 0x50; /* 5 * 32 bit words */ pay->tcp.control = tcp_ctl; pay->tcp.window = htons(0x7FFF); pay->tcp.checksum = htons(0x0000); pay->tcp.urg = htons(0x0000); buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE; break; case SOCK_DGRAM: pay->udp.source_port = src_port; pay->udp.dest_port = dest_port; pay->udp.length = htons(8 + payload_len); pay->udp.checksum = htons(0x0000); buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE; break; } if (payload && payload_len > 0) { memcpy(buf, payload, payload_len); } *_packet_len = packet_len - icmp_truncate_len; return base; } static int swrap_get_pcap_fd(const char *fname) { static int fd = -1; if (fd != -1) return fd; fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644); if (fd != -1) { struct swrap_file_hdr file_hdr; file_hdr.magic = 0xA1B2C3D4; file_hdr.version_major = 0x0002; file_hdr.version_minor = 0x0004; file_hdr.timezone = 0x00000000; file_hdr.sigfigs = 0x00000000; file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX; file_hdr.link_type = 0x0065; /* 101 RAW IP */ if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) { close(fd); fd = -1; } return fd; } fd = open(fname, O_WRONLY|O_APPEND, 0644); return fd; } static uint8_t *swrap_marshall_packet(struct socket_info *si, const struct sockaddr *addr, enum swrap_packet_type type, const void *buf, size_t len, size_t *packet_len) { const struct sockaddr *src_addr; const struct sockaddr *dest_addr; unsigned long tcp_seqno = 0; unsigned long tcp_ack = 0; unsigned char tcp_ctl = 0; int unreachable = 0; struct timeval tv; switch (si->family) { case AF_INET: break; #ifdef HAVE_IPV6 case AF_INET6: break; #endif default: return NULL; } switch (type) { case SWRAP_CONNECT_SEND: if (si->type != SOCK_STREAM) return NULL; src_addr = si->myname; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x02; /* SYN */ si->io.pck_snd += 1; break; case SWRAP_CONNECT_RECV: if (si->type != SOCK_STREAM) return NULL; dest_addr = si->myname; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x12; /** SYN,ACK */ si->io.pck_rcv += 1; break; case SWRAP_CONNECT_UNREACH: if (si->type != SOCK_STREAM) return NULL; dest_addr = si->myname; src_addr = addr; /* Unreachable: resend the data of SWRAP_CONNECT_SEND */ tcp_seqno = si->io.pck_snd - 1; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x02; /* SYN */ unreachable = 1; break; case SWRAP_CONNECT_ACK: if (si->type != SOCK_STREAM) return NULL; src_addr = si->myname; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x10; /* ACK */ break; case SWRAP_ACCEPT_SEND: if (si->type != SOCK_STREAM) return NULL; dest_addr = si->myname; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x02; /* SYN */ si->io.pck_rcv += 1; break; case SWRAP_ACCEPT_RECV: if (si->type != SOCK_STREAM) return NULL; src_addr = si->myname; dest_addr = addr; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x12; /* SYN,ACK */ si->io.pck_snd += 1; break; case SWRAP_ACCEPT_ACK: if (si->type != SOCK_STREAM) return NULL; dest_addr = si->myname; src_addr = addr; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x10; /* ACK */ break; case SWRAP_SEND: src_addr = si->myname; dest_addr = si->peername; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x18; /* PSH,ACK */ si->io.pck_snd += len; break; case SWRAP_SEND_RST: dest_addr = si->myname; src_addr = si->peername; if (si->type == SOCK_DGRAM) { return swrap_marshall_packet(si, si->peername, SWRAP_SENDTO_UNREACH, buf, len, packet_len); } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /** RST,ACK */ break; case SWRAP_PENDING_RST: dest_addr = si->myname; src_addr = si->peername; if (si->type == SOCK_DGRAM) { return NULL; } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /* RST,ACK */ break; case SWRAP_RECV: dest_addr = si->myname; src_addr = si->peername; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x18; /* PSH,ACK */ si->io.pck_rcv += len; break; case SWRAP_RECV_RST: dest_addr = si->myname; src_addr = si->peername; if (si->type == SOCK_DGRAM) { return NULL; } tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x14; /* RST,ACK */ break; case SWRAP_SENDTO: src_addr = si->myname; dest_addr = addr; si->io.pck_snd += len; break; case SWRAP_SENDTO_UNREACH: dest_addr = si->myname; src_addr = addr; unreachable = 1; break; case SWRAP_RECVFROM: dest_addr = si->myname; src_addr = addr; si->io.pck_rcv += len; break; case SWRAP_CLOSE_SEND: if (si->type != SOCK_STREAM) return NULL; src_addr = si->myname; dest_addr = si->peername; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x11; /* FIN, ACK */ si->io.pck_snd += 1; break; case SWRAP_CLOSE_RECV: if (si->type != SOCK_STREAM) return NULL; dest_addr = si->myname; src_addr = si->peername; tcp_seqno = si->io.pck_rcv; tcp_ack = si->io.pck_snd; tcp_ctl = 0x11; /* FIN,ACK */ si->io.pck_rcv += 1; break; case SWRAP_CLOSE_ACK: if (si->type != SOCK_STREAM) return NULL; src_addr = si->myname; dest_addr = si->peername; tcp_seqno = si->io.pck_snd; tcp_ack = si->io.pck_rcv; tcp_ctl = 0x10; /* ACK */ break; default: return NULL; } swrapGetTimeOfDay(&tv); return swrap_packet_init(&tv, src_addr, dest_addr, si->type, (const uint8_t *)buf, len, tcp_seqno, tcp_ack, tcp_ctl, unreachable, packet_len); } static void swrap_dump_packet(struct socket_info *si, const struct sockaddr *addr, enum swrap_packet_type type, const void *buf, size_t len) { const char *file_name; uint8_t *packet; size_t packet_len = 0; int fd; file_name = socket_wrapper_pcap_file(); if (!file_name) { return; } packet = swrap_marshall_packet(si, addr, type, buf, len, &packet_len); if (!packet) { return; } fd = swrap_get_pcap_fd(file_name); if (fd != -1) { if (write(fd, packet, packet_len) != packet_len) { free(packet); return; } } free(packet); } _PUBLIC_ int swrap_socket(int family, int type, int protocol) { struct socket_info *si; struct socket_info_fd *fi; int fd; int real_type = type; #ifdef SOCK_CLOEXEC real_type &= ~SOCK_CLOEXEC; #endif #ifdef SOCK_NONBLOCK real_type &= ~SOCK_NONBLOCK; #endif if (!socket_wrapper_dir()) { return real_socket(family, type, protocol); } switch (family) { case AF_INET: #ifdef HAVE_IPV6 case AF_INET6: #endif break; case AF_UNIX: return real_socket(family, type, protocol); default: errno = EAFNOSUPPORT; return -1; } switch (real_type) { case SOCK_STREAM: break; case SOCK_DGRAM: break; default: errno = EPROTONOSUPPORT; return -1; } switch (protocol) { case 0: break; case 6: if (real_type == SOCK_STREAM) { break; } /*fall through*/ case 17: if (real_type == SOCK_DGRAM) { break; } /*fall through*/ default: errno = EPROTONOSUPPORT; return -1; } /* We must call real_socket with type, from the caller, not the version we removed SOCK_CLOEXEC and SOCK_NONBLOCK from */ fd = real_socket(AF_UNIX, type, 0); if (fd == -1) return -1; si = (struct socket_info *)calloc(1, sizeof(struct socket_info)); if (si == NULL) { errno = ENOMEM; return -1; } si->family = family; /* however, the rest of the socket_wrapper code expects just * the type, not the flags */ si->type = real_type; si->protocol = protocol; fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { free(si); errno = ENOMEM; return -1; } fi->fd = fd; SWRAP_DLIST_ADD(si->fds, fi); SWRAP_DLIST_ADD(sockets, si); return fd; } _PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { struct socket_info *parent_si, *child_si; struct socket_info_fd *child_fi; int fd; struct sockaddr_un un_addr; socklen_t un_addrlen = sizeof(un_addr); struct sockaddr_un un_my_addr; socklen_t un_my_addrlen = sizeof(un_my_addr); struct sockaddr *my_addr; socklen_t my_addrlen, len; int ret; parent_si = find_socket_info(s); if (!parent_si) { return real_accept(s, addr, addrlen); } /* * assume out sockaddr have the same size as the in parent * socket family */ my_addrlen = socket_length(parent_si->family); if (my_addrlen <= 0) { errno = EINVAL; return -1; } my_addr = (struct sockaddr *)malloc(my_addrlen); if (my_addr == NULL) { return -1; } memset(&un_addr, 0, sizeof(un_addr)); memset(&un_my_addr, 0, sizeof(un_my_addr)); ret = real_accept(s, (struct sockaddr *)(void *)&un_addr, &un_addrlen); if (ret == -1) { free(my_addr); return ret; } fd = ret; len = my_addrlen; ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen, parent_si->family, my_addr, &len); if (ret == -1) { free(my_addr); close(fd); return ret; } child_si = (struct socket_info *)malloc(sizeof(struct socket_info)); memset(child_si, 0, sizeof(*child_si)); child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (child_fi == NULL) { free(child_si); free(my_addr); close(fd); errno = ENOMEM; return -1; } child_fi->fd = fd; SWRAP_DLIST_ADD(child_si->fds, child_fi); child_si->family = parent_si->family; child_si->type = parent_si->type; child_si->protocol = parent_si->protocol; child_si->bound = 1; child_si->is_server = 1; child_si->connected = 1; child_si->peername_len = len; child_si->peername = sockaddr_dup(my_addr, len); if (addr != NULL && addrlen != NULL) { size_t copy_len = MIN(*addrlen, len); if (copy_len > 0) { memcpy(addr, my_addr, copy_len); } *addrlen = len; } ret = real_getsockname(fd, (struct sockaddr *)(void *)&un_my_addr, &un_my_addrlen); if (ret == -1) { free(child_fi); free(child_si); close(fd); return ret; } len = my_addrlen; ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen, child_si->family, my_addr, &len); if (ret == -1) { free(child_fi); free(child_si); free(my_addr); close(fd); return ret; } child_si->myname_len = len; child_si->myname = sockaddr_dup(my_addr, len); free(my_addr); SWRAP_DLIST_ADD(sockets, child_si); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0); return fd; } static int autobind_start_init; static int autobind_start; /* using sendto() or connect() on an unbound socket would give the recipient no way to reply, as unlike UDP and TCP, a unix domain socket can't auto-assign emphemeral port numbers, so we need to assign it here. Note: this might change the family from ipv6 to ipv4 */ static int swrap_auto_bind(int fd, struct socket_info *si, int family) { struct sockaddr_un un_addr; int i; char type; int ret; int port; struct stat st; if (autobind_start_init != 1) { autobind_start_init = 1; autobind_start = getpid(); autobind_start %= 50000; autobind_start += 10000; } un_addr.sun_family = AF_UNIX; switch (family) { case AF_INET: { struct sockaddr_in in; switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP; break; default: errno = ESOCKTNOSUPPORT; return -1; } memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(127<<24 | socket_wrapper_default_iface()); si->myname_len = sizeof(in); si->myname = sockaddr_dup(&in, si->myname_len); break; } #ifdef HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 in6; if (si->family != family) { errno = ENETUNREACH; return -1; } switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP_V6; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP_V6; break; default: errno = ESOCKTNOSUPPORT; return -1; } memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; in6.sin6_addr = *swrap_ipv6(); in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface(); si->myname_len = sizeof(in6); si->myname = sockaddr_dup(&in6, si->myname_len); break; } #endif default: errno = ESOCKTNOSUPPORT; return -1; } if (autobind_start > 60000) { autobind_start = 10000; } for (i=0;i<1000;i++) { port = autobind_start + i; snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, socket_wrapper_default_iface(), port); if (stat(un_addr.sun_path, &st) == 0) continue; ret = real_bind(fd, (struct sockaddr *)(void *)&un_addr, sizeof(un_addr)); if (ret == -1) return ret; si->tmp_path = strdup(un_addr.sun_path); si->bound = 1; autobind_start = port + 1; break; } if (i == 1000) { errno = ENFILE; return -1; } si->family = family; set_port(si->family, port, si->myname); return 0; } _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen) { int ret; struct sockaddr_un un_addr; struct socket_info *si = find_socket_info(s); int bcast = 0; if (!si) { return real_connect(s, serv_addr, addrlen); } if (si->bound == 0) { ret = swrap_auto_bind(s, si, serv_addr->sa_family); if (ret == -1) return -1; } if (si->family != serv_addr->sa_family) { errno = EINVAL; return -1; } ret = sockaddr_convert_to_un(si, serv_addr, addrlen, &un_addr, 0, &bcast); if (ret == -1) return -1; if (bcast) { errno = ENETUNREACH; return -1; } if (si->type == SOCK_DGRAM) { si->defer_connect = 1; ret = 0; } else { swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0); ret = real_connect(s, (struct sockaddr *)(void *)&un_addr, sizeof(struct sockaddr_un)); } /* to give better errors */ if (ret == -1 && errno == ENOENT) { errno = EHOSTUNREACH; } if (ret == 0) { si->peername_len = addrlen; si->peername = sockaddr_dup(serv_addr, addrlen); si->connected = 1; swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0); swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0); } else { swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0); } return ret; } _PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen) { int ret; struct sockaddr_un un_addr; struct socket_info *si = find_socket_info(s); if (!si) { return real_bind(s, myaddr, addrlen); } si->myname_len = addrlen; si->myname = sockaddr_dup(myaddr, addrlen); ret = sockaddr_convert_to_un(si, myaddr, addrlen, &un_addr, 1, &si->bcast); if (ret == -1) return -1; unlink(un_addr.sun_path); ret = real_bind(s, (struct sockaddr *)(void *)&un_addr, sizeof(struct sockaddr_un)); if (ret == 0) { si->bound = 1; } return ret; } _PUBLIC_ int swrap_listen(int s, int backlog) { int ret; struct socket_info *si = find_socket_info(s); if (!si) { return real_listen(s, backlog); } ret = real_listen(s, backlog); return ret; } _PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen) { struct socket_info *si = find_socket_info(s); if (!si) { return real_getpeername(s, name, addrlen); } if (!si->peername) { errno = ENOTCONN; return -1; } memcpy(name, si->peername, si->peername_len); *addrlen = si->peername_len; return 0; } _PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen) { struct socket_info *si = find_socket_info(s); if (!si) { return real_getsockname(s, name, addrlen); } memcpy(name, si->myname, si->myname_len); *addrlen = si->myname_len; return 0; } _PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { struct socket_info *si = find_socket_info(s); if (!si) { return real_getsockopt(s, level, optname, optval, optlen); } if (level == SOL_SOCKET) { return real_getsockopt(s, level, optname, optval, optlen); } errno = ENOPROTOOPT; return -1; } _PUBLIC_ int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { struct socket_info *si = find_socket_info(s); if (!si) { return real_setsockopt(s, level, optname, optval, optlen); } if (level == SOL_SOCKET) { return real_setsockopt(s, level, optname, optval, optlen); } switch (si->family) { case AF_INET: return 0; #ifdef HAVE_IPV6 case AF_INET6: return 0; #endif default: errno = ENOPROTOOPT; return -1; } } _PUBLIC_ int swrap_ioctl(int s, int r, void *p) { int ret; struct socket_info *si = find_socket_info(s); int value; if (!si) { return real_ioctl(s, r, p); } ret = real_ioctl(s, r, p); switch (r) { case FIONREAD: value = *((int *)p); if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) { swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); } else if (value == 0) { /* END OF FILE */ swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); } break; } return ret; } static ssize_t swrap_sendmsg_before(int fd, struct socket_info *si, struct msghdr *msg, struct iovec *tmp_iov, struct sockaddr_un *tmp_un, const struct sockaddr_un **to_un, const struct sockaddr **to, int *bcast) { size_t i, len = 0; ssize_t ret; if (to_un) { *to_un = NULL; } if (to) { *to = NULL; } if (bcast) { *bcast = 0; } switch (si->type) { case SOCK_STREAM: if (!si->connected) { errno = ENOTCONN; return -1; } if (msg->msg_iovlen == 0) { break; } /* * cut down to 1500 byte packets for stream sockets, * which makes it easier to format PCAP capture files * (as the caller will simply continue from here) */ for (i=0; i < msg->msg_iovlen; i++) { size_t nlen; nlen = len + msg->msg_iov[i].iov_len; if (nlen > 1500) { break; } } msg->msg_iovlen = i; if (msg->msg_iovlen == 0) { *tmp_iov = msg->msg_iov[0]; tmp_iov->iov_len = MIN(tmp_iov->iov_len, 1500); msg->msg_iov = tmp_iov; msg->msg_iovlen = 1; } break; case SOCK_DGRAM: if (si->connected) { if (msg->msg_name) { errno = EISCONN; return -1; } } else { const struct sockaddr *msg_name; msg_name = (const struct sockaddr *)msg->msg_name; if (msg_name == NULL) { errno = ENOTCONN; return -1; } ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen, tmp_un, 0, bcast); if (ret == -1) return -1; if (to_un) { *to_un = tmp_un; } if (to) { *to = msg_name; } msg->msg_name = tmp_un; msg->msg_namelen = sizeof(*tmp_un); } if (si->bound == 0) { ret = swrap_auto_bind(fd, si, si->family); if (ret == -1) return -1; } if (!si->defer_connect) { break; } ret = sockaddr_convert_to_un(si, si->peername, si->peername_len, tmp_un, 0, NULL); if (ret == -1) return -1; ret = real_connect(fd, (struct sockaddr *)(void *)tmp_un, sizeof(*tmp_un)); /* to give better errors */ if (ret == -1 && errno == ENOENT) { errno = EHOSTUNREACH; } if (ret == -1) { return ret; } si->defer_connect = 0; break; default: errno = EHOSTUNREACH; return -1; } return 0; } static void swrap_sendmsg_after(struct socket_info *si, struct msghdr *msg, const struct sockaddr *to, ssize_t ret) { int saved_errno = errno; size_t i, len = 0; uint8_t *buf; off_t ofs = 0; size_t avail = 0; size_t remain; /* to give better errors */ if (ret == -1 && saved_errno == ENOENT) { saved_errno = EHOSTUNREACH; } for (i=0; i < msg->msg_iovlen; i++) { avail += msg->msg_iov[i].iov_len; } if (ret == -1) { remain = MIN(80, avail); } else { remain = ret; } /* we capture it as one single packet */ buf = (uint8_t *)malloc(remain); if (!buf) { /* we just not capture the packet */ errno = saved_errno; return; } for (i=0; i < msg->msg_iovlen; i++) { size_t this_time = MIN(remain, msg->msg_iov[i].iov_len); memcpy(buf + ofs, msg->msg_iov[i].iov_base, this_time); ofs += this_time; remain -= this_time; } len = ofs; switch (si->type) { case SOCK_STREAM: if (ret == -1) { swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len); swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0); } else { swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len); } break; case SOCK_DGRAM: if (si->connected) { to = si->peername; } if (ret == -1) { swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len); swrap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len); } else { swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len); } break; } free(buf); errno = saved_errno; } _PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { struct sockaddr_un un_addr; socklen_t un_addrlen = sizeof(un_addr); int ret; struct socket_info *si = find_socket_info(s); struct sockaddr_storage ss; socklen_t ss_len = sizeof(ss); if (!si) { return real_recvfrom(s, buf, len, flags, from, fromlen); } if (!from) { from = (struct sockaddr *)(void *)&ss; fromlen = &ss_len; } if (si->type == SOCK_STREAM) { /* cut down to 1500 byte packets for stream sockets, * which makes it easier to format PCAP capture files * (as the caller will simply continue from here) */ len = MIN(len, 1500); } /* irix 6.4 forgets to null terminate the sun_path string :-( */ memset(&un_addr, 0, sizeof(un_addr)); ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)(void *)&un_addr, &un_addrlen); if (ret == -1) return ret; if (sockaddr_convert_from_un(si, &un_addr, un_addrlen, si->family, from, fromlen) == -1) { return -1; } swrap_dump_packet(si, from, SWRAP_RECVFROM, buf, ret); return ret; } _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; const struct sockaddr_un *to_un = NULL; ssize_t ret; struct socket_info *si = find_socket_info(s); int bcast = 0; if (!si) { return real_sendto(s, buf, len, flags, to, tolen); } tmp.iov_base = discard_const_p(char, buf); tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = discard_const_p(struct sockaddr, to); /* optional address */ msg.msg_namelen = tolen; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #if 0 /* not available on solaris */ msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast); if (ret == -1) return -1; buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; if (bcast) { struct stat st; unsigned int iface; unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port); char type; type = SOCKET_TYPE_CHAR_UDP; for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); if (stat(un_addr.sun_path, &st) != 0) continue; /* ignore the any errors in broadcast sends */ real_sendto(s, buf, len, flags, (struct sockaddr *)(void *)&un_addr, sizeof(un_addr)); } swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len); return len; } ret = real_sendto(s, buf, len, flags, (struct sockaddr *)msg.msg_name, msg.msg_namelen); swrap_sendmsg_after(si, &msg, to, ret); return ret; } _PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags) { int ret; struct socket_info *si = find_socket_info(s); if (!si) { return real_recv(s, buf, len, flags); } if (si->type == SOCK_STREAM) { /* cut down to 1500 byte packets for stream sockets, * which makes it easier to format PCAP capture files * (as the caller will simply continue from here) */ len = MIN(len, 1500); } ret = real_recv(s, buf, len, flags); if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) { swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret == 0) { /* END OF FILE */ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret > 0) { swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret); } return ret; } _PUBLIC_ ssize_t swrap_read(int s, void *buf, size_t len) { int ret; struct socket_info *si = find_socket_info(s); if (!si) { return real_read(s, buf, len); } if (si->type == SOCK_STREAM) { /* cut down to 1500 byte packets for stream sockets, * which makes it easier to format PCAP capture files * (as the caller will simply continue from here) */ len = MIN(len, 1500); } ret = real_read(s, buf, len); if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) { swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret == 0) { /* END OF FILE */ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret > 0) { swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret); } return ret; } _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; ssize_t ret; struct socket_info *si = find_socket_info(s); if (!si) { return real_send(s, buf, len, flags); } tmp.iov_base = discard_const_p(char, buf); tmp.iov_len = len; ZERO_STRUCT(msg); msg.msg_name = NULL; /* optional address */ msg.msg_namelen = 0; /* size of address */ msg.msg_iov = &tmp; /* scatter/gather array */ msg.msg_iovlen = 1; /* # elements in msg_iov */ #if 0 /* not available on solaris */ msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL); if (ret == -1) return -1; buf = msg.msg_iov[0].iov_base; len = msg.msg_iov[0].iov_len; ret = real_send(s, buf, len, flags); swrap_sendmsg_after(si, &msg, NULL, ret); return ret; } _PUBLIC_ ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; const struct sockaddr_un *to_un = NULL; const struct sockaddr *to = NULL; ssize_t ret; struct socket_info *si = find_socket_info(s); int bcast = 0; if (!si) { return real_sendmsg(s, omsg, flags); } tmp.iov_base = NULL; tmp.iov_len = 0; msg = *omsg; #if 0 msg.msg_name = omsg->msg_name; /* optional address */ msg.msg_namelen = omsg->msg_namelen; /* size of address */ msg.msg_iov = omsg->msg_iov; /* scatter/gather array */ msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */ /* the following is not available on solaris */ msg.msg_control = omsg->msg_control; /* ancillary data, see below */ msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */ msg.msg_flags = omsg->msg_flags; /* flags on received message */ #endif ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast); if (ret == -1) return -1; if (bcast) { struct stat st; unsigned int iface; unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port); char type; size_t i, len = 0; uint8_t *buf; off_t ofs = 0; size_t avail = 0; size_t remain; for (i=0; i < msg.msg_iovlen; i++) { avail += msg.msg_iov[i].iov_len; } len = avail; remain = avail; /* we capture it as one single packet */ buf = (uint8_t *)malloc(remain); if (!buf) { return -1; } for (i=0; i < msg.msg_iovlen; i++) { size_t this_time = MIN(remain, msg.msg_iov[i].iov_len); memcpy(buf + ofs, msg.msg_iov[i].iov_base, this_time); ofs += this_time; remain -= this_time; } type = SOCKET_TYPE_CHAR_UDP; for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) { snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); if (stat(un_addr.sun_path, &st) != 0) continue; msg.msg_name = &un_addr; /* optional address */ msg.msg_namelen = sizeof(un_addr); /* size of address */ /* ignore the any errors in broadcast sends */ real_sendmsg(s, &msg, flags); } swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len); free(buf); return len; } ret = real_sendmsg(s, &msg, flags); swrap_sendmsg_after(si, &msg, to, ret); return ret; } int swrap_readv(int s, const struct iovec *vector, size_t count) { int ret; struct socket_info *si = find_socket_info(s); struct iovec v; if (!si) { return real_readv(s, vector, count); } if (!si->connected) { errno = ENOTCONN; return -1; } if (si->type == SOCK_STREAM && count > 0) { /* cut down to 1500 byte packets for stream sockets, * which makes it easier to format PCAP capture files * (as the caller will simply continue from here) */ size_t i, len = 0; for (i=0; i < count; i++) { size_t nlen; nlen = len + vector[i].iov_len; if (nlen > 1500) { break; } } count = i; if (count == 0) { v = vector[0]; v.iov_len = MIN(v.iov_len, 1500); vector = &v; count = 1; } } ret = real_readv(s, vector, count); if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) { swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret == 0) { /* END OF FILE */ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0); } else if (ret > 0) { uint8_t *buf; off_t ofs = 0; size_t i; size_t remain = ret; /* we capture it as one single packet */ buf = (uint8_t *)malloc(ret); if (!buf) { /* we just not capture the packet */ errno = 0; return ret; } for (i=0; i < count; i++) { size_t this_time = MIN(remain, vector[i].iov_len); memcpy(buf + ofs, vector[i].iov_base, this_time); ofs += this_time; remain -= this_time; } swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret); free(buf); } return ret; } int swrap_writev(int s, const struct iovec *vector, size_t count) { struct msghdr msg; struct iovec tmp; struct sockaddr_un un_addr; ssize_t ret; struct socket_info *si = find_socket_info(s); if (!si) { return real_writev(s, vector, count); } tmp.iov_base = NULL; tmp.iov_len = 0; ZERO_STRUCT(msg); msg.msg_name = NULL; /* optional address */ msg.msg_namelen = 0; /* size of address */ msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */ msg.msg_iovlen = count; /* # elements in msg_iov */ #if 0 /* not available on solaris */ msg.msg_control = NULL; /* ancillary data, see below */ msg.msg_controllen = 0; /* ancillary data buffer len */ msg.msg_flags = 0; /* flags on received message */ #endif ret = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL); if (ret == -1) return -1; ret = real_writev(s, msg.msg_iov, msg.msg_iovlen); swrap_sendmsg_after(si, &msg, NULL, ret); return ret; } _PUBLIC_ int swrap_close(int fd) { struct socket_info *si = find_socket_info(fd); struct socket_info_fd *fi; int ret; if (!si) { return real_close(fd); } for (fi = si->fds; fi; fi = fi->next) { if (fi->fd == fd) { SWRAP_DLIST_REMOVE(si->fds, fi); free(fi); break; } } if (si->fds) { /* there are still references left */ return real_close(fd); } SWRAP_DLIST_REMOVE(sockets, si); if (si->myname && si->peername) { swrap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0); } ret = real_close(fd); if (si->myname && si->peername) { swrap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0); swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0); } if (si->myname) free(si->myname); if (si->peername) free(si->peername); if (si->tmp_path) { unlink(si->tmp_path); free(si->tmp_path); } free(si); return ret; } _PUBLIC_ int swrap_dup(int fd) { struct socket_info *si; struct socket_info_fd *fi; si = find_socket_info(fd); if (!si) { return real_dup(fd); } fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { errno = ENOMEM; return -1; } fi->fd = real_dup(fd); if (fi->fd == -1) { int saved_errno = errno; free(fi); errno = saved_errno; return -1; } SWRAP_DLIST_ADD(si->fds, fi); return fi->fd; } _PUBLIC_ int swrap_dup2(int fd, int newfd) { struct socket_info *si; struct socket_info_fd *fi; si = find_socket_info(fd); if (!si) { return real_dup2(fd, newfd); } if (find_socket_info(newfd)) { /* dup2() does an implicit close of newfd, which we * need to emulate */ swrap_close(newfd); } fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { errno = ENOMEM; return -1; } fi->fd = real_dup2(fd, newfd); if (fi->fd == -1) { int saved_errno = errno; free(fi); errno = saved_errno; return -1; } SWRAP_DLIST_ADD(si->fds, fi); return fi->fd; } ctdb-2.5.1.dfsg/lib/socket_wrapper/wscript_build0000644000175000017500000000043112245023514021616 0ustar mathieumathieu#!/usr/bin/env python bld.SAMBA_LIBRARY('socket_wrapper', source='socket_wrapper.c', group='base_libraries', private_library=True, enabled=bld.CONFIG_SET('SOCKET_WRAPPER'), deps='replace') ctdb-2.5.1.dfsg/lib/socket_wrapper/config.m40000644000175000017500000000110312245023514020525 0ustar mathieumathieuAC_ARG_ENABLE(socket-wrapper, AS_HELP_STRING([--enable-socket-wrapper], [Turn on socket wrapper library (default=no)])) DEFAULT_TEST_OPTIONS= HAVE_SOCKET_WRAPPER=no if eval "test x$developer = xyes"; then enable_socket_wrapper=yes fi if eval "test x$enable_socket_wrapper = xyes"; then AC_DEFINE(SOCKET_WRAPPER,1,[Use socket wrapper library]) DEFAULT_TEST_OPTIONS=--socket-wrapper HAVE_SOCKET_WRAPPER=yes SOCKET_WRAPPER_OBJS="lib/socket_wrapper/socket_wrapper.o" fi AC_SUBST(DEFAULT_TEST_OPTIONS) AC_SUBST(HAVE_SOCKET_WRAPPER) AC_SUBST(SOCKET_WRAPPER_OBJS) ctdb-2.5.1.dfsg/lib/socket_wrapper/socket_wrapper.h0000644000175000017500000001264712245023514022236 0ustar mathieumathieu/* * Copyright (C) Jelmer Vernooij 2005 * Copyright (C) Stefan Metzmacher 2006 * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef __SOCKET_WRAPPER_H__ #define __SOCKET_WRAPPER_H__ const char *socket_wrapper_dir(void); unsigned int socket_wrapper_default_iface(void); int swrap_socket(int family, int type, int protocol); int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen); int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen); int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen); int swrap_listen(int s, int backlog); int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen); int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen); int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen); int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); ssize_t swrap_sendmsg(int s, const struct msghdr *msg, int flags); ssize_t swrap_recvmsg(int s, struct msghdr *msg, int flags); int swrap_ioctl(int s, int req, void *ptr); ssize_t swrap_recv(int s, void *buf, size_t len, int flags); ssize_t swrap_read(int s, void *buf, size_t len); ssize_t swrap_send(int s, const void *buf, size_t len, int flags); int swrap_readv(int s, const struct iovec *vector, size_t count); int swrap_writev(int s, const struct iovec *vector, size_t count); int swrap_close(int); int swrap_dup(int oldfd); int swrap_dup2(int oldfd, int newfd); #ifdef SOCKET_WRAPPER_REPLACE #ifdef accept #undef accept #endif #define accept(s,addr,addrlen) swrap_accept(s,addr,addrlen) #ifdef connect #undef connect #endif #define connect(s,serv_addr,addrlen) swrap_connect(s,serv_addr,addrlen) #ifdef bind #undef bind #endif #define bind(s,myaddr,addrlen) swrap_bind(s,myaddr,addrlen) #ifdef listen #undef listen #endif #define listen(s,blog) swrap_listen(s,blog) #ifdef getpeername #undef getpeername #endif #define getpeername(s,name,addrlen) swrap_getpeername(s,name,addrlen) #ifdef getsockname #undef getsockname #endif #define getsockname(s,name,addrlen) swrap_getsockname(s,name,addrlen) #ifdef getsockopt #undef getsockopt #endif #define getsockopt(s,level,optname,optval,optlen) swrap_getsockopt(s,level,optname,optval,optlen) #ifdef setsockopt #undef setsockopt #endif #define setsockopt(s,level,optname,optval,optlen) swrap_setsockopt(s,level,optname,optval,optlen) #ifdef recvfrom #undef recvfrom #endif #define recvfrom(s,buf,len,flags,from,fromlen) swrap_recvfrom(s,buf,len,flags,from,fromlen) #ifdef sendto #undef sendto #endif #define sendto(s,buf,len,flags,to,tolen) swrap_sendto(s,buf,len,flags,to,tolen) #ifdef sendmsg #undef sendmsg #endif #define sendmsg(s,msg,flags) swrap_sendmsg(s,msg,flags) #ifdef recvmsg #undef recvmsg #endif #define recvmsg(s,msg,flags) swrap_recvmsg(s,msg,flags) #ifdef ioctl #undef ioctl #endif #define ioctl(s,req,ptr) swrap_ioctl(s,req,ptr) #ifdef recv #undef recv #endif #define recv(s,buf,len,flags) swrap_recv(s,buf,len,flags) #ifdef read #undef read #endif #define read(s,buf,len) swrap_read(s,buf,len) #ifdef send #undef send #endif #define send(s,buf,len,flags) swrap_send(s,buf,len,flags) #ifdef readv #undef readv #endif #define readv(s, vector, count) swrap_readv(s,vector, count) #ifdef writev #undef writev #endif #define writev(s, vector, count) swrap_writev(s,vector, count) #ifdef socket #undef socket #endif #define socket(domain,type,protocol) swrap_socket(domain,type,protocol) #ifdef close #undef close #endif #define close(s) swrap_close(s) #ifdef dup #undef dup #endif #define dup(s) swrap_dup(s) #ifdef dup2 #undef dup2 #endif #define dup2(s, s2) swrap_dup2(s, s2) #endif /* SOCKET_WRAPPER_REPLACE */ #endif /* __SOCKET_WRAPPER_H__ */ ctdb-2.5.1.dfsg/lib/socket_wrapper/testsuite.c0000644000175000017500000000666612245023514021236 0ustar mathieumathieu/* Unix SMB/CIFS implementation. local testing of the socket wrapper Copyright (C) Jelmer Vernooij 2007 This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #include "includes.h" #include "system/network.h" #include "../socket_wrapper/socket_wrapper.h" #include "torture/torture.h" static char *old_dir = NULL; static char *old_iface = NULL; static void backup_env(void) { old_dir = getenv("SOCKET_WRAPPER_DIR"); old_iface = getenv("SOCKET_WRAPPER_DEFAULT_IFACE"); } static void restore_env(void) { if (old_dir == NULL) unsetenv("SOCKET_WRAPPER_DIR"); else setenv("SOCKET_WRAPPER_DIR", old_dir, 1); if (old_iface == NULL) unsetenv("SOCKET_WRAPPER_DEFAULT_IFACE"); else setenv("SOCKET_WRAPPER_DEFAULT_IFACE", old_iface, 1); } static bool test_socket_wrapper_dir(struct torture_context *tctx) { backup_env(); setenv("SOCKET_WRAPPER_DIR", "foo", 1); torture_assert_str_equal(tctx, socket_wrapper_dir(), "foo", "setting failed"); setenv("SOCKET_WRAPPER_DIR", "./foo", 1); torture_assert_str_equal(tctx, socket_wrapper_dir(), "foo", "setting failed"); unsetenv("SOCKET_WRAPPER_DIR"); torture_assert_str_equal(tctx, socket_wrapper_dir(), NULL, "resetting failed"); restore_env(); return true; } static bool test_swrap_socket(struct torture_context *tctx) { backup_env(); setenv("SOCKET_WRAPPER_DIR", "foo", 1); torture_assert_int_equal(tctx, swrap_socket(1337, 1337, 0), -1, "unknown address family fails"); torture_assert_int_equal(tctx, errno, EAFNOSUPPORT, "correct errno set"); torture_assert_int_equal(tctx, swrap_socket(AF_INET, 1337, 0), -1, "unknown type fails"); torture_assert_int_equal(tctx, errno, EPROTONOSUPPORT, "correct errno set"); torture_assert_int_equal(tctx, swrap_socket(AF_INET, SOCK_DGRAM, 10), -1, "unknown protocol fails"); torture_assert_int_equal(tctx, errno, EPROTONOSUPPORT, "correct errno set"); restore_env(); return true; } unsigned int socket_wrapper_default_iface(void); static bool test_socket_wrapper_default_iface(struct torture_context *tctx) { backup_env(); unsetenv("SOCKET_WRAPPER_DEFAULT_IFACE"); torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 1, "unset"); setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "2", 1); torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 2, "unset"); setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "bla", 1); torture_assert_int_equal(tctx, socket_wrapper_default_iface(), 1, "unset"); restore_env(); return true; } struct torture_suite *torture_local_socket_wrapper(TALLOC_CTX *mem_ctx) { struct torture_suite *suite = torture_suite_create(mem_ctx, "socket-wrapper"); torture_suite_add_simple_test(suite, "socket_wrapper_dir", test_socket_wrapper_dir); torture_suite_add_simple_test(suite, "socket", test_swrap_socket); torture_suite_add_simple_test(suite, "socket_wrapper_default_iface", test_socket_wrapper_default_iface); return suite; } ctdb-2.5.1.dfsg/lib/socket_wrapper/wscript0000644000175000017500000000103412245023514020437 0ustar mathieumathieu#!/usr/bin/env python import Options def set_options(opt): gr = opt.option_group('developer options') gr.add_option('--enable-socket-wrapper', help=("Turn on socket wrapper library (default=no)"), action="store_true", dest='enable_socket_wrapper', default=False) def configure(conf): if (Options.options.enable_socket_wrapper or Options.options.developer or Options.options.enable_selftest): conf.DEFINE('SOCKET_WRAPPER', 1) conf.ADD_GLOBAL_DEPENDENCY('socket_wrapper') ctdb-2.5.1.dfsg/lib/replace/0000755000175000017500000000000012245023514015406 5ustar mathieumathieuctdb-2.5.1.dfsg/lib/replace/README0000644000175000017500000000304012245023514016263 0ustar mathieumathieuThis subsystem ensures that we can always use a certain core set of functions and types, that are either provided by the OS or by replacement functions / definitions in this subsystem. The aim is to try to stick to POSIX functions in here as much as possible. Convenience functions that are available on no platform at all belong in other subsystems (such as LIBUTIL). The following functions are guaranteed: ftruncate strlcpy strlcat mktime rename initgroups memmove strdup setlinebuf vsyslog timegm setenv unsetenv strndup strnlen waitpid seteuid setegid asprintf snprintf vasprintf vsnprintf opendir readdir telldir seekdir clock_gettime closedir dlopen dlclose dlsym dlerror chroot bzero strerror errno mkdtemp mkstemp (a secure one!) pread pwrite chown lchown readline (the library) inet_ntoa inet_ntop inet_pton inet_aton strtoll strtoull socketpair strptime getaddrinfo freeaddrinfo getnameinfo gai_strerror getifaddrs freeifaddrs utime utimes dup2 link readlink symlink realpath poll setproctitle Types: bool socklen_t uint{8,16,32,64}_t int{8,16,32,64}_t intptr_t sig_atomic_t blksize_t blkcnt_t Constants: PATH_NAME_MAX UINT{16,32,64}_MAX INT32_MAX RTLD_LAZY HOST_NAME_MAX UINT16_MAX UINT32_MAX UINT64_MAX CHAR_BIT Macros: va_copy __FUNCTION__ __FILE__ __LINE__ __LINESTR__ __location__ __STRING __STRINGSTRING MIN MAX QSORT_CAST ZERO_STRUCT ZERO_STRUCTP ZERO_STRUCTPN ZERO_ARRAY ARRAY_SIZE PTR_DIFF Headers: stdint.h stdbool.h Optional C keywords: volatile Prerequisites: memset (for bzero) syslog (for vsyslog) mktemp (for mkstemp and mkdtemp) ctdb-2.5.1.dfsg/lib/replace/libreplace_cc.m40000644000175000017500000001174712245023514020431 0ustar mathieumathieu AC_DEFUN_ONCE(AC__LIBREPLACE_ONLY_CC_CHECKS_START, [ echo "LIBREPLACE_CC_CHECKS: START" ]) AC_DEFUN_ONCE(AC__LIBREPLACE_ONLY_CC_CHECKS_END, [ echo "LIBREPLACE_CC_CHECKS: END" ]) dnl dnl dnl AC_LIBREPLACE_CC_CHECKS dnl dnl Note: we need to use m4_define instead of AC_DEFUN because dnl of the ordering of tests dnl dnl m4_define(AC_LIBREPLACE_CC_CHECKS, [ AC__LIBREPLACE_ONLY_CC_CHECKS_START dnl stop the C89 attempt by autoconf - if autoconf detects -Ae it will enable it dnl which conflicts with C99 on HPUX ac_cv_prog_cc_Ae=no savedCFLAGS=$CFLAGS AC_PROG_CC CFLAGS=$savedCFLAGS dnl don't try for C99 if we are using gcc, as otherwise we dnl lose immediate structure constants if test x"$GCC" != x"yes" ; then AC_PROG_CC_C99 fi if test x"$GCC" = x"yes" ; then AC_MSG_CHECKING([for version of gcc]) GCC_VERSION=`$CC -dumpversion` AC_MSG_RESULT(${GCC_VERSION}) fi AC_USE_SYSTEM_EXTENSIONS AC_C_BIGENDIAN AC_C_INLINE LIBREPLACE_C99_STRUCT_INIT([],[AC_MSG_WARN([c99 structure initializer are not supported])]) AC_PROG_INSTALL AC_ISC_POSIX AC_N_DEFINE(_XOPEN_SOURCE_EXTENDED) AC_MSG_CHECKING(checking getconf LFS_CFLAGS for large file support flags) LFS_CFLAGS=`(getconf LFS_CFLAGS) 2>/dev/null` || LFS_CFLAGS="" AC_MSG_RESULT(${LFS_CFLAGS}) if test "x$LFS_CFLAGS" != 'x-1' || test "x$LFS_CFLAGS" != "xundefined"; then CFLAGS="$CFLAGS $LFS_CFLAGS" fi AC_SYS_LARGEFILE dnl Add #include for broken IRIX header files case "$host_os" in *irix6*) AC_ADD_INCLUDE() AC_N_DEFINE(_XOPEN_SOURCE,600) AC_N_DEFINE(_BSD_TYPES) ;; *hpux*) # mmap on HPUX is completely broken... AC_DEFINE(MMAP_BLACKLIST, 1, [Whether MMAP is broken]) if test "`uname -r`" = "B.11.00" -o "`uname -r`" = "B.11.11"; then AC_MSG_WARN([Enabling HPUX 11.00/11.11 header bug workaround]) CFLAGS="$CFLAGS -Dpread=pread64 -Dpwrite=pwrite64" fi if test "`uname -r`" = "B.11.23"; then AC_MSG_WARN([Enabling HPUX 11.23 machine/sys/getppdp.h bug workaround]) CFLAGS="$CFLAGS -D_MACHINE_SYS_GETPPDP_INCLUDED" fi ;; *aix*) AC_DEFINE(BROKEN_STRNDUP, 1, [Whether strndup is broken]) AC_DEFINE(BROKEN_STRNLEN, 1, [Whether strnlen is broken]) if test "${GCC}" != "yes"; then ## for funky AIX compiler using strncpy() CFLAGS="$CFLAGS -D_LINUX_SOURCE_COMPAT -qmaxmem=32000" fi ;; *osf*) # this brings in socklen_t AC_N_DEFINE(_XOPEN_SOURCE,600) AC_N_DEFINE(_OSF_SOURCE) ;; # # VOS may need to have POSIX support and System V compatibility enabled. # *vos*) case "$CFLAGS" in *-D_POSIX_C_SOURCE*);; *) CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=200112L" AC_DEFINE(_POSIX_C_SOURCE, 200112L, [Whether to enable POSIX support]) ;; esac case "$CFLAGS" in *-D_SYSV*|*-D_SVID_SOURCE*);; *) CFLAGS="$CFLAGS -D_SYSV" AC_DEFINE(_SYSV, 1, [Whether to enable System V compatibility]) ;; esac ;; esac # Do not check for standards.h on darwin, we get nasty warnings on # OS/X Lion. Probably a positive-list of OS'es like IRIX and AIX # would be the better choice, but this seems to work fine case "$host_os" in *darwin*) ;; *) AC_CHECK_HEADERS([standards.h]) ;; esac # Solaris needs HAVE_LONG_LONG defined AC_CHECK_TYPES(long long) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_CHECK_TYPE(int8_t, char) AC_CHECK_TYPE(uint8_t, unsigned char) AC_CHECK_TYPE(int16_t, short) AC_CHECK_TYPE(uint16_t, unsigned short) if test $ac_cv_sizeof_int -eq 4 ; then AC_CHECK_TYPE(int32_t, int) AC_CHECK_TYPE(uint32_t, unsigned int) elif test $ac_cv_size_long -eq 4 ; then AC_CHECK_TYPE(int32_t, long) AC_CHECK_TYPE(uint32_t, unsigned long) else AC_MSG_ERROR([LIBREPLACE no 32-bit type found]) fi AC_CHECK_TYPE(int64_t, long long) AC_CHECK_TYPE(uint64_t, unsigned long long) AC_CHECK_TYPE(size_t, unsigned int) AC_CHECK_TYPE(ssize_t, int) AC_CHECK_SIZEOF(off_t) AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(ssize_t) AC_CHECK_TYPES([intptr_t, uintptr_t, ptrdiff_t]) if test x"$ac_cv_type_long_long" != x"yes";then AC_MSG_ERROR([LIBREPLACE needs type 'long long']) fi if test $ac_cv_sizeof_long_long -lt 8;then AC_MSG_ERROR([LIBREPLACE needs sizeof(long long) >= 8]) fi ############################################ # check if the compiler can do immediate structures AC_SUBST(libreplace_cv_immediate_structures) AC_CACHE_CHECK([for immediate structures],libreplace_cv_immediate_structures,[ AC_TRY_COMPILE([ #include ],[ typedef struct {unsigned x;} FOOBAR; #define X_FOOBAR(x) ((FOOBAR) { x }) #define FOO_ONE X_FOOBAR(1) FOOBAR f = FOO_ONE; static const struct { FOOBAR y; } f2[] = { {FOO_ONE} }; static const FOOBAR f3[] = {FOO_ONE}; ], libreplace_cv_immediate_structures=yes, libreplace_cv_immediate_structures=no, libreplace_cv_immediate_structures=cross) ]) if test x"$libreplace_cv_immediate_structures" = x"yes"; then AC_DEFINE(HAVE_IMMEDIATE_STRUCTURES,1,[Whether the compiler supports immediate structures]) fi AC__LIBREPLACE_ONLY_CC_CHECKS_END ]) dnl end AC_LIBREPLACE_CC_CHECKS ctdb-2.5.1.dfsg/lib/replace/libreplace_macros.m40000644000175000017500000002465412245023514021331 0ustar mathieumathieu# # This is a collection of useful autoconf macros # ############################################ # Check if the compiler handles c99 struct initialization, and if not try -AC99 and -c99 flags # Usage: LIBREPLACE_C99_STRUCT_INIT(success-action,failure-action) # changes CFLAGS to add -AC99 or -c99 if needed AC_DEFUN([LIBREPLACE_C99_STRUCT_INIT], [ saved_CFLAGS="$CFLAGS"; c99_init=no if test x"$c99_init" = x"no"; then AC_MSG_CHECKING(for C99 designated initializers) CFLAGS="$saved_CFLAGS"; AC_TRY_COMPILE([#include ], [ struct foo {int x;char y;}; struct foo bar = { .y = 'X', .x = 1 }; ], [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)]) fi if test x"$c99_init" = x"no"; then AC_MSG_CHECKING(for C99 designated initializers with -AC99) CFLAGS="$saved_CFLAGS -AC99"; AC_TRY_COMPILE([#include ], [ struct foo {int x;char y;}; struct foo bar = { .y = 'X', .x = 1 }; ], [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)]) fi if test x"$c99_init" = x"no"; then AC_MSG_CHECKING(for C99 designated initializers with -qlanglvl=extc99) CFLAGS="$saved_CFLAGS -qlanglvl=extc99"; AC_TRY_COMPILE([#include ], [ struct foo {int x;char y;}; struct foo bar = { .y = 'X', .x = 1 }; ], [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)]) fi if test x"$c99_init" = x"no"; then AC_MSG_CHECKING(for C99 designated initializers with -qlanglvl=stdc99) CFLAGS="$saved_CFLAGS -qlanglvl=stdc99"; AC_TRY_COMPILE([#include ], [ struct foo {int x;char y;}; struct foo bar = { .y = 'X', .x = 1 }; ], [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)]) fi if test x"$c99_init" = x"no"; then AC_MSG_CHECKING(for C99 designated initializers with -c99) CFLAGS="$saved_CFLAGS -c99" AC_TRY_COMPILE([#include ], [ struct foo {int x;char y;}; struct foo bar = { .y = 'X', .x = 1 }; ], [AC_MSG_RESULT(yes); c99_init=yes],[AC_MSG_RESULT(no)]) fi if test "`uname`" = "HP-UX"; then if test "$ac_cv_c_compiler_gnu" = no; then # special override for broken HP-UX compiler - I can't find a way to test # this properly (its a compiler bug) CFLAGS="$CFLAGS -AC99"; c99_init=yes; fi fi if test x"$c99_init" = x"yes"; then saved_CFLAGS="" $1 else CFLAGS="$saved_CFLAGS" saved_CFLAGS="" $2 fi ]) dnl AC_PROG_CC_FLAG(flag) AC_DEFUN(AC_PROG_CC_FLAG, [AC_CACHE_CHECK(whether ${CC-cc} accepts -$1, ac_cv_prog_cc_$1, [echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -$1 -c conftest.c 2>&1`"; then ac_cv_prog_cc_$1=yes else ac_cv_prog_cc_$1=no fi rm -f conftest* ])]) dnl see if a declaration exists for a function or variable dnl defines HAVE_function_DECL if it exists dnl AC_HAVE_DECL(var, includes) AC_DEFUN(AC_HAVE_DECL, [ AC_CACHE_CHECK([for $1 declaration],ac_cv_have_$1_decl,[ AC_TRY_COMPILE([$2],[int i = (int)$1], ac_cv_have_$1_decl=yes,ac_cv_have_$1_decl=no)]) if test x"$ac_cv_have_$1_decl" = x"yes"; then AC_DEFINE([HAVE_]translit([$1], [a-z], [A-Z])[_DECL],1,[Whether $1() is available]) fi ]) # AC_CHECK_LIB_EXT(LIBRARY, [EXT_LIBS], [FUNCTION], # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], # [ADD-ACTION-IF-FOUND],[OTHER-LIBRARIES]) # ------------------------------------------------------ # # Use a cache variable name containing both the library and function name, # because the test really is for library $1 defining function $3, not # just for library $1. Separate tests with the same $1 and different $3s # may have different results. # # Note that using directly AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$3]) # is asking for trouble, since AC_CHECK_LIB($lib, fun) would give # ac_cv_lib_$lib_fun, which is definitely not what was meant. Hence # the AS_LITERAL_IF indirection. # # FIXME: This macro is extremely suspicious. It DEFINEs unconditionally, # whatever the FUNCTION, in addition to not being a *S macro. Note # that the cache does depend upon the function we are looking for. # # It is on purpose we used `ac_check_lib_ext_save_LIBS' and not just # `ac_save_LIBS': there are many macros which don't want to see `LIBS' # changed but still want to use AC_CHECK_LIB_EXT, so they save `LIBS'. # And ``ac_save_LIBS' is too tempting a name, so let's leave them some # freedom. AC_DEFUN([AC_CHECK_LIB_EXT], [ AH_CHECK_LIB_EXT([$1]) ac_check_lib_ext_save_LIBS=$LIBS LIBS="-l$1 $$2 $7 $LIBS" AS_LITERAL_IF([$1], [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1])], [AS_VAR_PUSHDEF([ac_Lib_ext], [ac_cv_lib_ext_$1''])])dnl m4_ifval([$3], [ AH_CHECK_FUNC_EXT([$3]) AS_LITERAL_IF([$1], [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1_$3])], [AS_VAR_PUSHDEF([ac_Lib_func], [ac_cv_lib_ext_$1''_$3])])dnl AC_CACHE_CHECK([for $3 in -l$1], ac_Lib_func, [AC_TRY_LINK_FUNC($3, [AS_VAR_SET(ac_Lib_func, yes); AS_VAR_SET(ac_Lib_ext, yes)], [AS_VAR_SET(ac_Lib_func, no); AS_VAR_SET(ac_Lib_ext, no)]) ]) AS_IF([test AS_VAR_GET(ac_Lib_func) = yes], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$3))])dnl AS_VAR_POPDEF([ac_Lib_func])dnl ],[ AC_CACHE_CHECK([for -l$1], ac_Lib_ext, [AC_TRY_LINK_FUNC([main], [AS_VAR_SET(ac_Lib_ext, yes)], [AS_VAR_SET(ac_Lib_ext, no)]) ]) ]) LIBS=$ac_check_lib_ext_save_LIBS AS_IF([test AS_VAR_GET(ac_Lib_ext) = yes], [m4_default([$4], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1)) case "$$2" in *-l$1*) ;; *) $2="-l$1 $$2" ;; esac]) [$6] ], [$5])dnl AS_VAR_POPDEF([ac_Lib_ext])dnl ])# AC_CHECK_LIB_EXT # AH_CHECK_LIB_EXT(LIBNAME) # --------------------- m4_define([AH_CHECK_LIB_EXT], [AH_TEMPLATE(AS_TR_CPP(HAVE_LIB$1), [Define to 1 if you have the `]$1[' library (-l]$1[).])]) dnl AC_SEARCH_LIBS_EXT(FUNCTION, SEARCH-LIBS, EXT_LIBS, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], dnl [OTHER-LIBRARIES]) dnl -------------------------------------------------------- dnl Search for a library defining FUNC, if it's not already available. AC_DEFUN([AC_SEARCH_LIBS_EXT], [AC_CACHE_CHECK([for library containing $1], [ac_cv_search_ext_$1], [ ac_func_search_ext_save_LIBS=$LIBS ac_cv_search_ext_$1=no AC_LINK_IFELSE([AC_LANG_CALL([], [$1])], [ac_cv_search_ext_$1="none required"]) if test "$ac_cv_search_ext_$1" = no; then for ac_lib in $2; do LIBS="-l$ac_lib $$3 $6 $ac_func_search_save_ext_LIBS" AC_LINK_IFELSE([AC_LANG_CALL([], [$1])], [ac_cv_search_ext_$1="-l$ac_lib" break]) done fi LIBS=$ac_func_search_ext_save_LIBS]) AS_IF([test "$ac_cv_search_ext_$1" != no], [test "$ac_cv_search_ext_$1" = "none required" || $3="$ac_cv_search_ext_$1 $$3" $4], [$5])dnl ]) dnl check for a function in a $LIBS and $OTHER_LIBS libraries variable. dnl AC_CHECK_FUNC_EXT(func,OTHER_LIBS,IF-TRUE,IF-FALSE) AC_DEFUN([AC_CHECK_FUNC_EXT], [ AH_CHECK_FUNC_EXT($1) ac_check_func_ext_save_LIBS=$LIBS LIBS="$2 $LIBS" AS_VAR_PUSHDEF([ac_var], [ac_cv_func_ext_$1])dnl AC_CACHE_CHECK([for $1], ac_var, [AC_LINK_IFELSE([AC_LANG_FUNC_LINK_TRY([$1])], [AS_VAR_SET(ac_var, yes)], [AS_VAR_SET(ac_var, no)])]) LIBS=$ac_check_func_ext_save_LIBS AS_IF([test AS_VAR_GET(ac_var) = yes], [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1])) $3], [$4])dnl AS_VAR_POPDEF([ac_var])dnl ])# AC_CHECK_FUNC # AH_CHECK_FUNC_EXT(FUNCNAME) # --------------------- m4_define([AH_CHECK_FUNC_EXT], [AH_TEMPLATE(AS_TR_CPP(HAVE_$1), [Define to 1 if you have the `]$1[' function.])]) dnl Define an AC_DEFINE with ifndef guard. dnl AC_N_DEFINE(VARIABLE [, VALUE]) AC_DEFUN([AC_N_DEFINE], [ AH_VERBATIM([$1], [ #ifndef $1 # undef $1 #endif ]) cat >>confdefs.h <<\EOF #ifndef $1 [#define] $1 m4_if($#, 1, 1, [$2]) #endif EOF ]) dnl Add an #include dnl AC_ADD_INCLUDE(VARIABLE) define(AC_ADD_INCLUDE, [cat >> confdefs.h <<\EOF [#include] $1 EOF ]) dnl remove an #include dnl AC_REMOVE_INCLUDE(VARIABLE) define(AC_REMOVE_INCLUDE, [ grep -v '[#include] $1' confdefs.h >confdefs.h.tmp cat confdefs.h.tmp > confdefs.h rm confdefs.h.tmp ]) dnl remove an #define dnl AC_REMOVE_DEFINE(VARIABLE) define(AC_REMOVE_DEFINE, [ grep -v '[#define] $1 ' confdefs.h |grep -v '[#define] $1[$]'>confdefs.h.tmp cat confdefs.h.tmp > confdefs.h rm confdefs.h.tmp ]) dnl AS_HELP_STRING is not available in autoconf 2.57, and AC_HELP_STRING is deprecated dnl in autoconf 2.59, so define AS_HELP_STRING to be AC_HELP_STRING unless it is already dnl defined. m4_ifdef([AS_HELP_STRING], , [m4_define([AS_HELP_STRING], m4_defn([AC_HELP_STRING]))]) dnl check if the prototype in the header matches the given one dnl AC_VERIFY_C_PROTOTYPE(prototype,functionbody,[IF-TRUE].[IF-FALSE],[extraheaders]) AC_DEFUN(AC_VERIFY_C_PROTOTYPE, [AC_CACHE_CHECK([for prototype $1], AS_TR_SH([ac_cv_c_prototype_$1]), AC_COMPILE_IFELSE([AC_LANG_SOURCE([ AC_INCLUDES_DEFAULT $5 $1 { $2 } ])],[ eval AS_TR_SH([ac_cv_c_prototype_$1])=yes ],[ eval AS_TR_SH([ac_cv_c_prototype_$1])=no ]) ) AS_IF([eval test $AS_TR_SH([ac_cv_c_prototype_$1]) = yes],[$3],[$4]) ]) AC_DEFUN(LIBREPLACE_PROVIDE_HEADER, [AC_CHECK_HEADER([$1], [ AC_CONFIG_COMMANDS(rm-$1, [rm -f $libreplacedir/$1], [libreplacedir=$libreplacedir]) ], [ AC_CONFIG_COMMANDS(mk-$1, [echo "#include \"replace.h\"" > $libreplacedir/$1], [libreplacedir=$libreplacedir]) ] ) ]) dnl AC_HAVE_TYPE(TYPE,INCLUDES) AC_DEFUN([AC_HAVE_TYPE], [ AC_REQUIRE([AC_HEADER_STDC]) cv=`echo "$1" | sed 'y%./+- %__p__%'` AC_MSG_CHECKING(for $1) AC_CACHE_VAL([ac_cv_type_$cv], AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ AC_INCLUDES_DEFAULT $2]], [[$1 foo;]])], [eval "ac_cv_type_$cv=yes"], [eval "ac_cv_type_$cv=no"]))dnl ac_foo=`eval echo \\$ac_cv_type_$cv` AC_MSG_RESULT($ac_foo) if test "$ac_foo" = yes; then ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'` if false; then AC_CHECK_TYPES($1) fi AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1']) fi ]) # AC_CHECK_VALUEOF(TYPE, [INCLUDES = DEFAULT-INCLUDES]) # --------------------------------------------------------------- AC_DEFUN([AC_CHECK_VALUEOF], [AS_LITERAL_IF(m4_translit([[$1]], [*], [p]), [], [m4_fatal([$0: requires literal arguments])])]dnl [ _AC_CACHE_CHECK_INT([value of $1], [AS_TR_SH([ac_cv_valueof_$1])], [(long int) ($1)], [AC_INCLUDES_DEFAULT([$2])], []) AC_DEFINE_UNQUOTED(AS_TR_CPP(valueof_$1), $AS_TR_SH([ac_cv_valueof_$1]), [The value of `$1'.]) ])# AC_CHECK_VALUEOF ctdb-2.5.1.dfsg/lib/replace/replace.c0000644000175000017500000004473112245023514017176 0ustar mathieumathieu/* Unix SMB/CIFS implementation. replacement routines for broken systems Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jelmer Vernooij 2005-2008 Copyright (C) Matthieu Patou 2010 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include "replace.h" #include "system/filesys.h" #include "system/time.h" #include "system/network.h" #include "system/passwd.h" #include "system/syslog.h" #include "system/locale.h" #include "system/wait.h" #ifdef _WIN32 #define mkdir(d,m) _mkdir(d) #endif void replace_dummy(void); void replace_dummy(void) {} #ifndef HAVE_FTRUNCATE /******************************************************************* ftruncate for operating systems that don't have it ********************************************************************/ int rep_ftruncate(int f, off_t l) { #ifdef HAVE_CHSIZE return chsize(f,l); #elif defined(F_FREESP) struct flock fl; fl.l_whence = 0; fl.l_len = 0; fl.l_start = l; fl.l_type = F_WRLCK; return fcntl(f, F_FREESP, &fl); #else #error "you must have a ftruncate function" #endif } #endif /* HAVE_FTRUNCATE */ #ifndef HAVE_STRLCPY /* like strncpy but does not 0 fill the buffer and always null terminates. bufsize is the size of the destination buffer */ size_t rep_strlcpy(char *d, const char *s, size_t bufsize) { size_t len = strlen(s); size_t ret = len; if (bufsize <= 0) return 0; if (len >= bufsize) len = bufsize-1; memcpy(d, s, len); d[len] = 0; return ret; } #endif #ifndef HAVE_STRLCAT /* like strncat but does not 0 fill the buffer and always null terminates. bufsize is the length of the buffer, which should be one more than the maximum resulting string length */ size_t rep_strlcat(char *d, const char *s, size_t bufsize) { size_t len1 = strlen(d); size_t len2 = strlen(s); size_t ret = len1 + len2; if (len1+len2 >= bufsize) { if (bufsize < (len1+1)) { return ret; } len2 = bufsize - (len1+1); } if (len2 > 0) { memcpy(d+len1, s, len2); d[len1+len2] = 0; } return ret; } #endif #ifndef HAVE_MKTIME /******************************************************************* a mktime() replacement for those who don't have it - contributed by C.A. Lademann Corrections by richard.kettlewell@kewill.com ********************************************************************/ #define MINUTE 60 #define HOUR 60*MINUTE #define DAY 24*HOUR #define YEAR 365*DAY time_t rep_mktime(struct tm *t) { struct tm *u; time_t epoch = 0; int n; int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, y, m, i; if(t->tm_year < 70) return((time_t)-1); n = t->tm_year + 1900 - 1; epoch = (t->tm_year - 70) * YEAR + ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY; y = t->tm_year + 1900; m = 0; for(i = 0; i < t->tm_mon; i++) { epoch += mon [m] * DAY; if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) epoch += DAY; if(++m > 11) { m = 0; y++; } } epoch += (t->tm_mday - 1) * DAY; epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec; if((u = localtime(&epoch)) != NULL) { t->tm_sec = u->tm_sec; t->tm_min = u->tm_min; t->tm_hour = u->tm_hour; t->tm_mday = u->tm_mday; t->tm_mon = u->tm_mon; t->tm_year = u->tm_year; t->tm_wday = u->tm_wday; t->tm_yday = u->tm_yday; t->tm_isdst = u->tm_isdst; } return(epoch); } #endif /* !HAVE_MKTIME */ #ifndef HAVE_INITGROUPS /**************************************************************************** some systems don't have an initgroups call ****************************************************************************/ int rep_initgroups(char *name, gid_t id) { #ifndef HAVE_SETGROUPS /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ errno = ENOSYS; return -1; #else /* HAVE_SETGROUPS */ #include gid_t *grouplst = NULL; int max_gr = NGROUPS_MAX; int ret; int i,j; struct group *g; char *gr; if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) { errno = ENOMEM; return -1; } grouplst[0] = id; i = 1; while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) { if (g->gr_gid == id) continue; j = 0; gr = g->gr_mem[0]; while (gr && (*gr != (char)NULL)) { if (strcmp(name,gr) == 0) { grouplst[i] = g->gr_gid; i++; gr = (char *)NULL; break; } gr = g->gr_mem[++j]; } } endgrent(); ret = setgroups(i, grouplst); free(grouplst); return ret; #endif /* HAVE_SETGROUPS */ } #endif /* HAVE_INITGROUPS */ #ifndef HAVE_MEMMOVE /******************************************************************* safely copies memory, ensuring no overlap problems. this is only used if the machine does not have its own memmove(). this is not the fastest algorithm in town, but it will do for our needs. ********************************************************************/ void *rep_memmove(void *dest,const void *src,int size) { unsigned long d,s; int i; if (dest==src || !size) return(dest); d = (unsigned long)dest; s = (unsigned long)src; if ((d >= (s+size)) || (s >= (d+size))) { /* no overlap */ memcpy(dest,src,size); return(dest); } if (d < s) { /* we can forward copy */ if (s-d >= sizeof(int) && !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) { /* do it all as words */ int *idest = (int *)dest; int *isrc = (int *)src; size /= sizeof(int); for (i=0;i= sizeof(int) && !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) { /* do it all as words */ int *idest = (int *)dest; int *isrc = (int *)src; size /= sizeof(int); for (i=size-1;i>=0;i--) idest[i] = isrc[i]; } else { /* simplest */ char *cdest = (char *)dest; char *csrc = (char *)src; for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; } } return(dest); } #endif /* HAVE_MEMMOVE */ #ifndef HAVE_STRDUP /**************************************************************************** duplicate a string ****************************************************************************/ char *rep_strdup(const char *s) { size_t len; char *ret; if (!s) return(NULL); len = strlen(s)+1; ret = (char *)malloc(len); if (!ret) return(NULL); memcpy(ret,s,len); return(ret); } #endif /* HAVE_STRDUP */ #ifndef HAVE_SETLINEBUF void rep_setlinebuf(FILE *stream) { setvbuf(stream, (char *)NULL, _IOLBF, 0); } #endif /* HAVE_SETLINEBUF */ #ifndef HAVE_VSYSLOG #ifdef HAVE_SYSLOG void rep_vsyslog (int facility_priority, const char *format, va_list arglist) { char *msg = NULL; vasprintf(&msg, format, arglist); if (!msg) return; syslog(facility_priority, "%s", msg); free(msg); } #endif /* HAVE_SYSLOG */ #endif /* HAVE_VSYSLOG */ #ifndef HAVE_STRNLEN /** Some platforms don't have strnlen **/ size_t rep_strnlen(const char *s, size_t max) { size_t len; for (len = 0; len < max; len++) { if (s[len] == '\0') { break; } } return len; } #endif #ifndef HAVE_STRNDUP /** Some platforms don't have strndup. **/ char *rep_strndup(const char *s, size_t n) { char *ret; n = strnlen(s, n); ret = malloc(n+1); if (!ret) return NULL; memcpy(ret, s, n); ret[n] = 0; return ret; } #endif #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4) int rep_waitpid(pid_t pid,int *status,int options) { return wait4(pid, status, options, NULL); } #endif #ifndef HAVE_SETEUID int rep_seteuid(uid_t euid) { #ifdef HAVE_SETRESUID return setresuid(-1, euid, -1); #else errno = ENOSYS; return -1; #endif } #endif #ifndef HAVE_SETEGID int rep_setegid(gid_t egid) { #ifdef HAVE_SETRESGID return setresgid(-1, egid, -1); #else errno = ENOSYS; return -1; #endif } #endif /******************************************************************* os/2 also doesn't have chroot ********************************************************************/ #ifndef HAVE_CHROOT int rep_chroot(const char *dname) { errno = ENOSYS; return -1; } #endif /***************************************************************** Possibly replace mkstemp if it is broken. *****************************************************************/ #ifndef HAVE_SECURE_MKSTEMP int rep_mkstemp(char *template) { /* have a reasonable go at emulating it. Hope that the system mktemp() isn't completely hopeless */ mktemp(template); if (template[0] == 0) return -1; return open(template, O_CREAT|O_EXCL|O_RDWR, 0600); } #endif #ifndef HAVE_MKDTEMP char *rep_mkdtemp(char *template) { char *dname; if ((dname = mktemp(template))) { if (mkdir(dname, 0700) >= 0) { return dname; } } return NULL; } #endif /***************************************************************** Watch out: this is not thread safe. *****************************************************************/ #ifndef HAVE_PREAD ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset) { if (lseek(__fd, __offset, SEEK_SET) != __offset) { return -1; } return read(__fd, __buf, __nbytes); } #endif /***************************************************************** Watch out: this is not thread safe. *****************************************************************/ #ifndef HAVE_PWRITE ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset) { if (lseek(__fd, __offset, SEEK_SET) != __offset) { return -1; } return write(__fd, __buf, __nbytes); } #endif #ifndef HAVE_STRCASESTR char *rep_strcasestr(const char *haystack, const char *needle) { const char *s; size_t nlen = strlen(needle); for (s=haystack;*s;s++) { if (toupper(*needle) == toupper(*s) && strncasecmp(s, needle, nlen) == 0) { return (char *)((uintptr_t)s); } } return NULL; } #endif #ifndef HAVE_STRTOK_R /* based on GLIBC version, copyright Free Software Foundation */ char *rep_strtok_r(char *s, const char *delim, char **save_ptr) { char *token; if (s == NULL) s = *save_ptr; s += strspn(s, delim); if (*s == '\0') { *save_ptr = s; return NULL; } token = s; s = strpbrk(token, delim); if (s == NULL) { *save_ptr = token + strlen(token); } else { *s = '\0'; *save_ptr = s + 1; } return token; } #endif #ifndef HAVE_STRTOLL long long int rep_strtoll(const char *str, char **endptr, int base) { #ifdef HAVE_STRTOQ return strtoq(str, endptr, base); #elif defined(HAVE___STRTOLL) return __strtoll(str, endptr, base); #elif SIZEOF_LONG == SIZEOF_LONG_LONG return (long long int) strtol(str, endptr, base); #else # error "You need a strtoll function" #endif } #else #ifdef HAVE_BSD_STRTOLL #ifdef HAVE_STRTOQ long long int rep_strtoll(const char *str, char **endptr, int base) { long long int nb = strtoq(str, endptr, base); /* In linux EINVAL is only returned if base is not ok */ if (errno == EINVAL) { if (base == 0 || (base >1 && base <37)) { /* Base was ok so it's because we were not * able to make the convertion. * Let's reset errno. */ errno = 0; } } return nb; } #else #error "You need the strtoq function" #endif /* HAVE_STRTOQ */ #endif /* HAVE_BSD_STRTOLL */ #endif /* HAVE_STRTOLL */ #ifndef HAVE_STRTOULL unsigned long long int rep_strtoull(const char *str, char **endptr, int base) { #ifdef HAVE_STRTOUQ return strtouq(str, endptr, base); #elif defined(HAVE___STRTOULL) return __strtoull(str, endptr, base); #elif SIZEOF_LONG == SIZEOF_LONG_LONG return (unsigned long long int) strtoul(str, endptr, base); #else # error "You need a strtoull function" #endif } #else #ifdef HAVE_BSD_STRTOLL #ifdef HAVE_STRTOUQ unsigned long long int rep_strtoull(const char *str, char **endptr, int base) { unsigned long long int nb = strtouq(str, endptr, base); /* In linux EINVAL is only returned if base is not ok */ if (errno == EINVAL) { if (base == 0 || (base >1 && base <37)) { /* Base was ok so it's because we were not * able to make the convertion. * Let's reset errno. */ errno = 0; } } return nb; } #else #error "You need the strtouq function" #endif /* HAVE_STRTOUQ */ #endif /* HAVE_BSD_STRTOLL */ #endif /* HAVE_STRTOULL */ #ifndef HAVE_SETENV int rep_setenv(const char *name, const char *value, int overwrite) { char *p; size_t l1, l2; int ret; if (!overwrite && getenv(name)) { return 0; } l1 = strlen(name); l2 = strlen(value); p = malloc(l1+l2+2); if (p == NULL) { return -1; } memcpy(p, name, l1); p[l1] = '='; memcpy(p+l1+1, value, l2); p[l1+l2+1] = 0; ret = putenv(p); if (ret != 0) { free(p); } return ret; } #endif #ifndef HAVE_UNSETENV int rep_unsetenv(const char *name) { extern char **environ; size_t len = strlen(name); size_t i, count; if (environ == NULL || getenv(name) == NULL) { return 0; } for (i=0;environ[i];i++) /* noop */ ; count=i; for (i=0;i= needlelen) { char *p = (char *)memchr(haystack, *(const char *)needle, haystacklen-(needlelen-1)); if (!p) return NULL; if (memcmp(p, needle, needlelen) == 0) { return p; } haystack = p+1; haystacklen -= (p - (const char *)haystack) + 1; } return NULL; } #endif #if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF) int rep_vdprintf(int fd, const char *format, va_list ap) { char *s = NULL; int ret; vasprintf(&s, format, ap); if (s == NULL) { errno = ENOMEM; return -1; } ret = write(fd, s, strlen(s)); free(s); return ret; } #endif #if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF) int rep_dprintf(int fd, const char *format, ...) { int ret; va_list ap; va_start(ap, format); ret = vdprintf(fd, format, ap); va_end(ap); return ret; } #endif #ifndef HAVE_GET_CURRENT_DIR_NAME char *rep_get_current_dir_name(void) { char buf[PATH_MAX+1]; char *p; p = getcwd(buf, sizeof(buf)); if (p == NULL) { return NULL; } return strdup(p); } #endif #ifndef HAVE_STRERROR_R int rep_strerror_r(int errnum, char *buf, size_t buflen) { char *s = strerror(errnum); if (strlen(s)+1 > buflen) { errno = ERANGE; return -1; } strncpy(buf, s, buflen); return 0; } #endif #ifndef HAVE_CLOCK_GETTIME int rep_clock_gettime(clockid_t clk_id, struct timespec *tp) { struct timeval tval; switch (clk_id) { case 0: /* CLOCK_REALTIME :*/ #ifdef HAVE_GETTIMEOFDAY_TZ gettimeofday(&tval,NULL); #else gettimeofday(&tval); #endif tp->tv_sec = tval.tv_sec; tp->tv_nsec = tval.tv_usec * 1000; break; default: errno = EINVAL; return -1; } return 0; } #endif #ifndef HAVE_MEMALIGN void *rep_memalign( size_t align, size_t size ) { #if defined(HAVE_POSIX_MEMALIGN) void *p = NULL; int ret = posix_memalign( &p, align, size ); if ( ret == 0 ) return p; return NULL; #else /* On *BSD systems memaligns doesn't exist, but memory will * be aligned on allocations of > pagesize. */ #if defined(SYSCONF_SC_PAGESIZE) size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); #elif defined(HAVE_GETPAGESIZE) size_t pagesize = (size_t)getpagesize(); #else size_t pagesize = (size_t)-1; #endif if (pagesize == (size_t)-1) { errno = ENOSYS; return NULL; } if (size < pagesize) { size = pagesize; } return malloc(size); #endif } #endif #ifndef HAVE_GETPEEREID int rep_getpeereid(int s, uid_t *uid, gid_t *gid) { #if defined(HAVE_PEERCRED) struct ucred cred; socklen_t cred_len = sizeof(struct ucred); int ret; #undef getsockopt ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len); if (ret != 0) { return -1; } if (cred_len != sizeof(struct ucred)) { errno = EINVAL; return -1; } *uid = cred.uid; *gid = cred.gid; return 0; #else errno = ENOSYS; return -1; #endif } #endif #ifndef HAVE_USLEEP int rep_usleep(useconds_t sec) { struct timeval tval; /* * Fake it with select... */ tval.tv_sec = 0; tval.tv_usec = usecs/1000; select(0,NULL,NULL,NULL,&tval); return 0; } #endif /* HAVE_USLEEP */ #ifndef HAVE_SETPROCTITLE void rep_setproctitle(const char *fmt, ...) { } #endif ctdb-2.5.1.dfsg/lib/replace/libreplace.m40000644000175000017500000003615512245023514017764 0ustar mathieumathieuAC_DEFUN_ONCE(AC_LIBREPLACE_LOCATION_CHECKS, [ echo "LIBREPLACE_LOCATION_CHECKS: START" dnl find the libreplace sources. This is meant to work both for dnl libreplace standalone builds, and builds of packages using libreplace libreplacedir="" libreplacepaths="$srcdir $srcdir/lib/replace $srcdir/libreplace $srcdir/../libreplace $srcdir/../replace $srcdir/../lib/replace $srcdir/../../../lib/replace" for d in $libreplacepaths; do if test -f "$d/replace.c"; then libreplacedir="$d" AC_SUBST(libreplacedir) break; fi done if test x"$libreplacedir" = "x"; then AC_MSG_ERROR([cannot find libreplace in $libreplacepaths]) fi LIBREPLACEOBJ="$libreplacedir/replace.o" AC_SUBST(LIBREPLACEOBJ) AC_CANONICAL_BUILD AC_CANONICAL_HOST AC_CANONICAL_TARGET echo "LIBREPLACE_LOCATION_CHECKS: END" ]) dnl end AC_LIBREPLACE_LOCATION_CHECKS AC_DEFUN_ONCE(AC_LIBREPLACE_BROKEN_CHECKS, [ echo "LIBREPLACE_BROKEN_CHECKS: START" dnl find the libreplace sources. This is meant to work both for dnl libreplace standalone builds, and builds of packages using libreplace libreplacedir="" libreplacepaths="$srcdir $srcdir/lib/replace $srcdir/libreplace $srcdir/../libreplace $srcdir/../replace $srcdir/../lib/replace $srcdir/../../../lib/replace" for d in $libreplacepaths; do if test -f "$d/replace.c"; then libreplacedir="$d" AC_SUBST(libreplacedir) break; fi done if test x"$libreplacedir" = "x"; then AC_MSG_ERROR([cannot find libreplace in $libreplacepaths]) fi LIBREPLACEOBJ="$libreplacedir/replace.o" AC_SUBST(LIBREPLACEOBJ) LIBREPLACEOBJ="${LIBREPLACEOBJ} $libreplacedir/snprintf.o $libreplacedir/xattr.o" AC_TYPE_UID_T AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_TYPE_PID_T AC_STRUCT_ST_RDEV AC_CHECK_TYPE(ino_t,unsigned) AC_CHECK_TYPE(loff_t,off_t) AC_CHECK_TYPE(offset_t,loff_t) AC_CHECK_TYPE(blksize_t,long) AC_CHECK_TYPE(blkcnt_t,long) AC_FUNC_MEMCMP AC_CHECK_FUNCS([pipe strftime srandom random srand rand usleep setbuffer lstat getpgrp utime utimes]) AC_CHECK_HEADERS(stdbool.h stdint.h sys/select.h) AC_CHECK_HEADERS(setjmp.h utime.h sys/wait.h) LIBREPLACE_PROVIDE_HEADER([stdint.h]) LIBREPLACE_PROVIDE_HEADER([stdbool.h]) AC_DEFINE(HAVE_LIBREPLACE, 1, [We have libreplace]) AC_CHECK_TYPE(bool, [AC_DEFINE(HAVE_BOOL, 1, [Whether the bool type is available])],, [ AC_INCLUDES_DEFAULT #ifdef HAVE_STDBOOL_H #include #endif] ) AC_CHECK_TYPE(_Bool, [AC_DEFINE(HAVE__Bool, 1, [Whether the _Bool type is available])],, [ AC_INCLUDES_DEFAULT #ifdef HAVE_STDBOOL_H #include #endif] ) AC_CHECK_HEADERS(linux/types.h) AC_CACHE_CHECK([for working mmap],libreplace_cv_HAVE_MMAP,[ AC_TRY_RUN([#include "$libreplacedir/test/shared_mmap.c"], libreplace_cv_HAVE_MMAP=yes,libreplace_cv_HAVE_MMAP=no,libreplace_cv_HAVE_MMAP=cross)]) if test x"$libreplace_cv_HAVE_MMAP" = x"yes"; then AC_DEFINE(HAVE_MMAP,1,[Whether mmap works]) fi AC_CACHE_CHECK([for working mremap],libreplace_cv_HAVE_MREMAP,[ AC_TRY_RUN([#include "$libreplacedir/test/shared_mremap.c"], libreplace_cv_HAVE_MREMAP=yes,libreplace_cv_HAVE_MREMAP=no,libreplace_cv_HAVE_MREMAP=cross)]) if test x"$libreplace_cv_HAVE_MREMAP" = x"yes"; then AC_DEFINE(HAVE_MREMAP,1,[Whether mremap works]) fi AC_CACHE_CHECK([for incoherent mmap],libreplace_cv_HAVE_INCOHERENT_MMAP,[ AC_TRY_RUN([#include "$libreplacedir/test/incoherent_mmap.c"], libreplace_cv_HAVE_INCOHERENT_MMAP=yes,libreplace_cv_HAVE_INCOHERENT_MMAP=no,libreplace_cv_HAVE_INCOHERENT_MMAP=cross)]) if test x"$libreplace_cv_HAVE_INCOHERENT_MMAP" = x"yes"; then AC_DEFINE(HAVE_INCOHERENT_MMAP,1,[Whether mmap is incoherent against write]) fi AC_CHECK_HEADERS(sys/syslog.h syslog.h) AC_CHECK_HEADERS(sys/time.h time.h) AC_CHECK_HEADERS(stdarg.h vararg.h) AC_CHECK_HEADERS(sys/mount.h mntent.h) AC_CHECK_HEADERS(stropts.h) AC_CHECK_HEADERS(unix.h) AC_CHECK_HEADERS(malloc.h) AC_CHECK_HEADERS(syscall.h) AC_CHECK_HEADERS(sys/syscall.h) AC_CHECK_HEADERS(sys/ucontext.h) AC_CHECK_FUNCS(syscall setuid seteuid setreuid setresuid setgid setegid setregid setresgid setgroups) AC_CHECK_FUNCS(chroot bzero strerror strerror_r memalign posix_memalign getpagesize) AC_CHECK_FUNCS(vsyslog setlinebuf mktime ftruncate chsize rename) AC_CHECK_FUNCS(waitpid wait4 strlcpy strlcat initgroups memmove strdup) AC_CHECK_FUNCS(pread pwrite strndup strcasestr strtok_r mkdtemp dup2 dprintf vdprintf) AC_CHECK_FUNCS(isatty chown lchown link readlink symlink realpath) AC_CHECK_FUNCS(fdatasync,,[ # if we didn't find it, look in librt (Solaris hides it there...) AC_CHECK_LIB(rt, fdatasync, [libreplace_cv_HAVE_FDATASYNC_IN_LIBRT=yes AC_DEFINE(HAVE_FDATASYNC, 1, Define to 1 if there is support for fdatasync)]) ]) AC_HAVE_DECL(fdatasync, [#include ]) AC_CHECK_FUNCS(clock_gettime,libreplace_cv_have_clock_gettime=yes,[ AC_CHECK_LIB(rt, clock_gettime, [libreplace_cv_HAVE_CLOCK_GETTIME_IN_LIBRT=yes libreplace_cv_have_clock_gettime=yes AC_DEFINE(HAVE_CLOCK_GETTIME, 1, Define to 1 if there is support for clock_gettime)]) ]) AC_CHECK_HEADERS(sys/attributes.h attr/xattr.h sys/xattr.h sys/extattr.h sys/uio.h) AC_CHECK_HEADERS(sys/ea.h sys/proplist.h) LIBREPLACE_FILESYS_LIBS="" ############################################ # Check for EA implementations case "$host_os" in *freebsd4* | *dragonfly* ) AC_DEFINE(BROKEN_EXTATTR, 1, [Does extattr API work]) ;; *) AC_SEARCH_LIBS(getxattr, [attr]) AC_CHECK_FUNCS(attr_get attr_getf attr_list attr_listf attropen attr_remove) AC_CHECK_FUNCS(attr_removef attr_set attr_setf extattr_delete_fd extattr_delete_file) AC_CHECK_FUNCS(extattr_get_fd extattr_get_file extattr_list_fd extattr_list_file) AC_CHECK_FUNCS(extattr_set_fd extattr_set_file fgetea fgetxattr flistea flistxattr) AC_CHECK_FUNCS(fremoveea fremovexattr fsetea fsetxattr getea getxattr listea) AC_CHECK_FUNCS(listxattr removeea removexattr setea setxattr) AC_CHECK_LIB_EXT(attr, LIBREPLACE_FILESYS_LIBS, flistea) AC_CHECK_LIB_EXT(attr, LIBREPLACE_FILESYS_LIBS, flistxattr) AC_CHECK_LIB_EXT(attr, LIBREPLACE_FILESYS_LIBS, attr_listf) AC_CHECK_LIB_EXT(attr, LIBREPLACE_FILESYS_LIBS, extattr_list_fd) ;; esac ######################################################## # Do xattr functions take additional options like on Darwin? if test x"$ac_cv_func_getxattr" = x"yes" ; then AC_CACHE_CHECK([whether xattr interface takes additional options], smb_attr_cv_xattr_add_opt, [ old_LIBS=$LIBS LIBS="$LIBS $LIBREPLACE_FILESYS_LIBS" AC_TRY_COMPILE([ #include #if HAVE_ATTR_XATTR_H #include #elif HAVE_SYS_XATTR_H #include #endif ],[ getxattr(0, 0, 0, 0, 0, 0); ], [smb_attr_cv_xattr_add_opt=yes], [smb_attr_cv_xattr_add_opt=no;LIBS=$old_LIBS]) ]) if test x"$smb_attr_cv_xattr_add_opt" = x"yes"; then AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [xattr functions have additional options]) fi fi AC_CHECK_FUNCS(get_current_dir_name) AC_HAVE_DECL(setresuid, [#include ]) AC_HAVE_DECL(setresgid, [#include ]) AC_HAVE_DECL(errno, [#include ]) AC_CACHE_CHECK([for secure mkstemp],libreplace_cv_HAVE_SECURE_MKSTEMP,[ AC_TRY_RUN([#include #include #include #include main() { struct stat st; char tpl[20]="/tmp/test.XXXXXX"; char tpl2[20]="/tmp/test.XXXXXX"; int fd = mkstemp(tpl); int fd2 = mkstemp(tpl2); if (fd == -1) { if (fd2 != -1) { unlink(tpl2); } exit(1); } if (fd2 == -1) exit(1); unlink(tpl); unlink(tpl2); if (fstat(fd, &st) != 0) exit(1); if ((st.st_mode & 0777) != 0600) exit(1); if (strcmp(tpl, "/tmp/test.XXXXXX") == 0) { exit(1); } if (strcmp(tpl, tpl2) == 0) { exit(1); } exit(0); }], libreplace_cv_HAVE_SECURE_MKSTEMP=yes, libreplace_cv_HAVE_SECURE_MKSTEMP=no, libreplace_cv_HAVE_SECURE_MKSTEMP=cross)]) if test x"$libreplace_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then AC_DEFINE(HAVE_SECURE_MKSTEMP,1,[Whether mkstemp is secure]) fi dnl Provided by snprintf.c: AC_CHECK_HEADERS(stdio.h strings.h) AC_CHECK_DECLS([snprintf, vsnprintf, asprintf, vasprintf]) AC_CHECK_FUNCS(snprintf vsnprintf asprintf vasprintf) AC_CACHE_CHECK([for C99 vsnprintf],libreplace_cv_HAVE_C99_VSNPRINTF,[ AC_TRY_RUN([ #include #include #include #include void foo(const char *format, ...) { va_list ap; int len; char buf[20]; long long l = 1234567890; l *= 100; va_start(ap, format); len = vsnprintf(buf, 0, format, ap); va_end(ap); if (len != 5) exit(1); va_start(ap, format); len = vsnprintf(0, 0, format, ap); va_end(ap); if (len != 5) exit(2); if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(3); if (snprintf(buf, 20, "%lld", l) != 12 || strcmp(buf, "123456789000") != 0) exit(4); if (snprintf(buf, 20, "%zu", 123456789) != 9 || strcmp(buf, "123456789") != 0) exit(5); if (snprintf(buf, 20, "%2\$d %1\$d", 3, 4) != 3 || strcmp(buf, "4 3") != 0) exit(6); if (snprintf(buf, 20, "%s", 0) < 3) exit(7); exit(0); } main() { foo("hello"); } ], libreplace_cv_HAVE_C99_VSNPRINTF=yes,libreplace_cv_HAVE_C99_VSNPRINTF=no,libreplace_cv_HAVE_C99_VSNPRINTF=cross)]) if test x"$libreplace_cv_HAVE_C99_VSNPRINTF" = x"yes"; then AC_DEFINE(HAVE_C99_VSNPRINTF,1,[Whether there is a C99 compliant vsnprintf]) fi dnl VA_COPY AC_CACHE_CHECK([for va_copy],libreplace_cv_HAVE_VA_COPY,[ AC_TRY_LINK([#include va_list ap1,ap2;], [va_copy(ap1,ap2);], libreplace_cv_HAVE_VA_COPY=yes,libreplace_cv_HAVE_VA_COPY=no)]) if test x"$libreplace_cv_HAVE_VA_COPY" = x"yes"; then AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available]) fi if test x"$libreplace_cv_HAVE_VA_COPY" != x"yes"; then AC_CACHE_CHECK([for __va_copy],libreplace_cv_HAVE___VA_COPY,[ AC_TRY_LINK([#include va_list ap1,ap2;], [__va_copy(ap1,ap2);], libreplace_cv_HAVE___VA_COPY=yes,libreplace_cv_HAVE___VA_COPY=no)]) if test x"$libreplace_cv_HAVE___VA_COPY" = x"yes"; then AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available]) fi fi dnl __FUNCTION__ macro AC_CACHE_CHECK([for __FUNCTION__ macro],libreplace_cv_HAVE_FUNCTION_MACRO,[ AC_TRY_COMPILE([#include ], [printf("%s\n", __FUNCTION__);], libreplace_cv_HAVE_FUNCTION_MACRO=yes,libreplace_cv_HAVE_FUNCTION_MACRO=no)]) if test x"$libreplace_cv_HAVE_FUNCTION_MACRO" = x"yes"; then AC_DEFINE(HAVE_FUNCTION_MACRO,1,[Whether there is a __FUNCTION__ macro]) else dnl __func__ macro AC_CACHE_CHECK([for __func__ macro],libreplace_cv_HAVE_func_MACRO,[ AC_TRY_COMPILE([#include ], [printf("%s\n", __func__);], libreplace_cv_HAVE_func_MACRO=yes,libreplace_cv_HAVE_func_MACRO=no)]) if test x"$libreplace_cv_HAVE_func_MACRO" = x"yes"; then AC_DEFINE(HAVE_func_MACRO,1,[Whether there is a __func__ macro]) fi fi AC_CHECK_HEADERS([sys/param.h limits.h]) AC_CHECK_TYPE(comparison_fn_t, [AC_DEFINE(HAVE_COMPARISON_FN_T, 1,[Whether or not we have comparison_fn_t])]) AC_HAVE_DECL(setenv, [#include ]) AC_CHECK_FUNCS(setenv unsetenv) AC_HAVE_DECL(environ, [#include ]) AC_CHECK_FUNCS(strnlen) AC_CHECK_FUNCS(strtoull __strtoull strtouq strtoll __strtoll strtoq) AC_CHECK_FUNCS(memmem) # this test disabled as we don't actually need __VA_ARGS__ yet AC_TRY_CPP([ #define eprintf(...) fprintf(stderr, __VA_ARGS__) eprintf("bla", "bar"); ], AC_DEFINE(HAVE__VA_ARGS__MACRO, 1, [Whether the __VA_ARGS__ macro is available])) AC_CACHE_CHECK([for sig_atomic_t type],libreplace_cv_sig_atomic_t, [ AC_TRY_COMPILE([ #include #if STDC_HEADERS #include #include #endif #include ],[sig_atomic_t i = 0], libreplace_cv_sig_atomic_t=yes,libreplace_cv_sig_atomic_t=no)]) if test x"$libreplace_cv_sig_atomic_t" = x"yes"; then AC_DEFINE(HAVE_SIG_ATOMIC_T_TYPE,1,[Whether we have the atomic_t variable type]) fi dnl Check if the C compiler understands volatile (it should, being ANSI). AC_CACHE_CHECK([that the C compiler understands volatile],libreplace_cv_volatile, [ AC_TRY_COMPILE([#include ],[volatile int i = 0], libreplace_cv_volatile=yes,libreplace_cv_volatile=no)]) if test x"$libreplace_cv_volatile" = x"yes"; then AC_DEFINE(HAVE_VOLATILE, 1, [Whether the C compiler understands volatile]) fi m4_include(system/config.m4) AC_CACHE_CHECK([for O_DIRECT flag to open(2)],libreplace_cv_HAVE_OPEN_O_DIRECT,[ AC_TRY_COMPILE([ #include #ifdef HAVE_FCNTL_H #include #endif], [int fd = open("/dev/null", O_DIRECT);], libreplace_cv_HAVE_OPEN_O_DIRECT=yes,libreplace_cv_HAVE_OPEN_O_DIRECT=no)]) if test x"$libreplace_cv_HAVE_OPEN_O_DIRECT" = x"yes"; then AC_DEFINE(HAVE_OPEN_O_DIRECT,1,[Whether the open(2) accepts O_DIRECT]) fi m4_include(dlfcn.m4) m4_include(strptime.m4) m4_include(win32.m4) m4_include(timegm.m4) m4_include(repdir.m4) m4_include(crypt.m4) if test x$libreplace_cv_have_clock_gettime = xyes ; then SMB_CHECK_CLOCK_ID(CLOCK_MONOTONIC) SMB_CHECK_CLOCK_ID(CLOCK_PROCESS_CPUTIME_ID) SMB_CHECK_CLOCK_ID(CLOCK_REALTIME) fi AC_CACHE_CHECK([for struct timespec type],libreplace_cv_struct_timespec, [ AC_TRY_COMPILE([ #include #if STDC_HEADERS #include #include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif ],[struct timespec ts;], libreplace_cv_struct_timespec=yes,libreplace_cv_struct_timespec=no)]) if test x"$libreplace_cv_struct_timespec" = x"yes"; then AC_DEFINE(HAVE_STRUCT_TIMESPEC,1,[Whether we have struct timespec]) fi AC_CACHE_CHECK([for ucontext_t type],libreplace_cv_ucontext_t, [ AC_TRY_COMPILE([ #include #if HAVE_SYS_UCONTEXT_H #include # endif ],[ucontext_t uc; sigaddset(&uc.uc_sigmask, SIGUSR1);], libreplace_cv_ucontext_t=yes,libreplace_cv_ucontext_t=no)]) if test x"$libreplace_cv_ucontext_t" = x"yes"; then AC_DEFINE(HAVE_UCONTEXT_T,1,[Whether we have ucontext_t]) fi AC_CHECK_FUNCS([printf memset memcpy],,[AC_MSG_ERROR([Required function not found])]) echo "LIBREPLACE_BROKEN_CHECKS: END" ]) dnl end AC_LIBREPLACE_BROKEN_CHECKS AC_DEFUN_ONCE(AC__LIBREPLACE_ALL_CHECKS_START, [ #LIBREPLACE_ALL_CHECKS: START" ]) AC_DEFUN_ONCE(AC__LIBREPLACE_ALL_CHECKS_END, [ #LIBREPLACE_ALL_CHECKS: END" ]) m4_define(AC_LIBREPLACE_ALL_CHECKS, [ AC__LIBREPLACE_ALL_CHECKS_START AC_LIBREPLACE_LOCATION_CHECKS AC_LIBREPLACE_CC_CHECKS AC_LIBREPLACE_BROKEN_CHECKS AC__LIBREPLACE_ALL_CHECKS_END CFLAGS="$CFLAGS -I$libreplacedir" ]) m4_include(libreplace_cc.m4) m4_include(libreplace_ld.m4) m4_include(libreplace_network.m4) m4_include(libreplace_macros.m4) dnl SMB_CHECK_CLOCK_ID(clockid) dnl Test whether the specified clock_gettime clock ID is available. If it dnl is, we define HAVE_clockid AC_DEFUN([SMB_CHECK_CLOCK_ID], [ AC_MSG_CHECKING(for $1) AC_TRY_LINK([ #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif ], [ clockid_t clk = $1; ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_$1, 1, [Whether the clock_gettime clock ID $1 is available]) ], [ AC_MSG_RESULT(no) ]) ]) m4_ifndef([AC_USE_SYSTEM_EXTENSIONS],[m4_include(autoconf-2.60.m4)]) ctdb-2.5.1.dfsg/lib/replace/timegm.m40000644000175000017500000000012512245023514017130 0ustar mathieumathieuAC_CHECK_FUNCS(timegm,[],[LIBREPLACEOBJ="${LIBREPLACEOBJ} $libreplacedir/timegm.o"]) ctdb-2.5.1.dfsg/lib/replace/snprintf.c0000644000175000017500000010666312245023514017431 0ustar mathieumathieu/* * NOTE: If you change this file, please merge it into rsync, samba, etc. */ /* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point... * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nast effects. * * More Recently: * Brandon Long 9/15/96 for mutt 0.43 * This was ugly. It is still ugly. I opted out of floating point * numbers, but the formatter understands just about everything * from the normal C string format, at least as far as I can tell from * the Solaris 2.5 printf(3S) man page. * * Brandon Long 10/22/97 for mutt 0.87.1 * Ok, added some minimal floating point support, which means this * probably requires libm on most operating systems. Don't yet * support the exponent (e,E) and sigfig (g,G). Also, fmtint() * was pretty badly broken, it just wasn't being exercised in ways * which showed it, so that's been fixed. Also, formated the code * to mutt conventions, and removed dead code left over from the * original. Also, there is now a builtin-test, just compile with: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm * and run snprintf for results. * * Thomas Roessler 01/27/98 for mutt 0.89i * The PGP code was using unsigned hexadecimal formats. * Unfortunately, unsigned formats simply didn't work. * * Michael Elkins 03/05/98 for mutt 0.90.8 * The original code assumed that both snprintf() and vsnprintf() were * missing. Some systems only have snprintf() but not vsnprintf(), so * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. * * Andrew Tridgell (tridge@samba.org) Oct 1998 * fixed handling of %.0f * added test for HAVE_LONG_DOUBLE * * tridge@samba.org, idra@samba.org, April 2001 * got rid of fcvt code (twas buggy and made testing harder) * added C99 semantics * * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 * actually print args for %g and %e * * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 * Since includes.h isn't included here, VA_COPY has to be defined here. I don't * see any include file that is guaranteed to be here, so I'm defining it * locally. Fixes AIX and Solaris builds. * * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 * put the ifdef for HAVE_VA_COPY in one place rather than in lots of * functions * * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 * Fix usage of va_list passed as an arg. Use __va_copy before using it * when it exists. * * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 * Fix incorrect zpadlen handling in fmtfp. * Thanks to Ollie Oldham for spotting it. * few mods to make it easier to compile the tests. * addedd the "Ollie" test to the floating point ones. * * Martin Pool (mbp@samba.org) April 2003 * Remove NO_CONFIG_H so that the test case can be built within a source * tree with less trouble. * Remove unnecessary SAFE_FREE() definition. * * Martin Pool (mbp@samba.org) May 2003 * Put in a prototype for dummy_snprintf() to quiet compiler warnings. * * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even * if the C library has some snprintf functions already. * * Darren Tucker (dtucker@zip.com.au) 2005 * Fix bug allowing read overruns of the source string with "%.*s" * Usually harmless unless the read runs outside the process' allocation * (eg if your malloc does guard pages) in which case it will segfault. * From OpenSSH. Also added test for same. * * Simo Sorce (idra@samba.org) Jan 2006 * * Add support for position independent parameters * fix fmtstr now it conforms to sprintf wrt min.max * **************************************************************/ #include "replace.h" #include "system/locale.h" #ifdef TEST_SNPRINTF /* need math library headers for testing */ /* In test mode, we pretend that this system doesn't have any snprintf * functions, regardless of what config.h says. */ # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # undef HAVE_C99_VSNPRINTF # undef HAVE_ASPRINTF # undef HAVE_VASPRINTF # include #endif /* TEST_SNPRINTF */ #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) /* only include stdio.h if we are not re-defining snprintf or vsnprintf */ #include /* make the compiler happy with an empty file */ void dummy_snprintf(void); void dummy_snprintf(void) {} #endif /* HAVE_SNPRINTF, etc */ /* yes this really must be a ||. Don't muck with this (tridge) */ #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double #else #define LDOUBLE double #endif #ifdef HAVE_LONG_LONG #define LLONG long long #else #define LLONG long #endif #ifndef VA_COPY #ifdef HAVE_VA_COPY #define VA_COPY(dest, src) va_copy(dest, src) #else #ifdef HAVE___VA_COPY #define VA_COPY(dest, src) __va_copy(dest, src) #else #define VA_COPY(dest, src) (dest) = (src) #endif #endif /* * dopr(): poor man's version of doprintf */ /* format read states */ #define DP_S_DEFAULT 0 #define DP_S_FLAGS 1 #define DP_S_MIN 2 #define DP_S_DOT 3 #define DP_S_MAX 4 #define DP_S_MOD 5 #define DP_S_CONV 6 #define DP_S_DONE 7 /* format flags - Bits */ #define DP_F_MINUS (1 << 0) #define DP_F_PLUS (1 << 1) #define DP_F_SPACE (1 << 2) #define DP_F_NUM (1 << 3) #define DP_F_ZERO (1 << 4) #define DP_F_UP (1 << 5) #define DP_F_UNSIGNED (1 << 6) /* Conversion Flags */ #define DP_C_CHAR 1 #define DP_C_SHORT 2 #define DP_C_LONG 3 #define DP_C_LDOUBLE 4 #define DP_C_LLONG 5 #define DP_C_SIZET 6 /* Chunk types */ #define CNK_FMT_STR 0 #define CNK_INT 1 #define CNK_OCTAL 2 #define CNK_UINT 3 #define CNK_HEX 4 #define CNK_FLOAT 5 #define CNK_CHAR 6 #define CNK_STRING 7 #define CNK_PTR 8 #define CNK_NUM 9 #define CNK_PRCNT 10 #define char_to_int(p) ((p)- '0') #ifndef MAX #define MAX(p,q) (((p) >= (q)) ? (p) : (q)) #endif struct pr_chunk { int type; /* chunk type */ int num; /* parameter number */ int min; int max; int flags; int cflags; int start; int len; LLONG value; LDOUBLE fvalue; char *strvalue; void *pnum; struct pr_chunk *min_star; struct pr_chunk *max_star; struct pr_chunk *next; }; struct pr_chunk_x { struct pr_chunk **chunks; int num; }; static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in); static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max); static void fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base, int min, int max, int flags); static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags); static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); static struct pr_chunk *new_chunk(void); static int add_cnk_list_entry(struct pr_chunk_x **list, int max_num, struct pr_chunk *chunk); static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) { char ch; int state; int pflag; int pnum; int pfirst; size_t currlen; va_list args; const char *base; struct pr_chunk *chunks = NULL; struct pr_chunk *cnk = NULL; struct pr_chunk_x *clist = NULL; int max_pos; int ret = -1; VA_COPY(args, args_in); state = DP_S_DEFAULT; pfirst = 1; pflag = 0; pnum = 0; max_pos = 0; base = format; ch = *format++; /* retrieve the string structure as chunks */ while (state != DP_S_DONE) { if (ch == '\0') state = DP_S_DONE; switch(state) { case DP_S_DEFAULT: if (cnk) { cnk->next = new_chunk(); cnk = cnk->next; } else { cnk = new_chunk(); } if (!cnk) goto done; if (!chunks) chunks = cnk; if (ch == '%') { state = DP_S_FLAGS; ch = *format++; } else { cnk->type = CNK_FMT_STR; cnk->start = format - base -1; while ((ch != '\0') && (ch != '%')) ch = *format++; cnk->len = format - base - cnk->start -1; } break; case DP_S_FLAGS: switch (ch) { case '-': cnk->flags |= DP_F_MINUS; ch = *format++; break; case '+': cnk->flags |= DP_F_PLUS; ch = *format++; break; case ' ': cnk->flags |= DP_F_SPACE; ch = *format++; break; case '#': cnk->flags |= DP_F_NUM; ch = *format++; break; case '0': cnk->flags |= DP_F_ZERO; ch = *format++; break; case 'I': /* internationalization not supported yet */ ch = *format++; break; default: state = DP_S_MIN; break; } break; case DP_S_MIN: if (isdigit((unsigned char)ch)) { cnk->min = 10 * cnk->min + char_to_int (ch); ch = *format++; } else if (ch == '$') { if (!pfirst && !pflag) { /* parameters must be all positioned or none */ goto done; } if (pfirst) { pfirst = 0; pflag = 1; } if (cnk->min == 0) /* what ?? */ goto done; cnk->num = cnk->min; cnk->min = 0; ch = *format++; } else if (ch == '*') { if (pfirst) pfirst = 0; cnk->min_star = new_chunk(); if (!cnk->min_star) /* out of memory :-( */ goto done; cnk->min_star->type = CNK_INT; if (pflag) { int num; ch = *format++; if (!isdigit((unsigned char)ch)) { /* parameters must be all positioned or none */ goto done; } for (num = 0; isdigit((unsigned char)ch); ch = *format++) { num = 10 * num + char_to_int(ch); } cnk->min_star->num = num; if (ch != '$') /* what ?? */ goto done; } else { cnk->min_star->num = ++pnum; } max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star); if (max_pos == 0) /* out of memory :-( */ goto done; ch = *format++; state = DP_S_DOT; } else { if (pfirst) pfirst = 0; state = DP_S_DOT; } break; case DP_S_DOT: if (ch == '.') { state = DP_S_MAX; ch = *format++; } else { state = DP_S_MOD; } break; case DP_S_MAX: if (isdigit((unsigned char)ch)) { if (cnk->max < 0) cnk->max = 0; cnk->max = 10 * cnk->max + char_to_int (ch); ch = *format++; } else if (ch == '$') { if (!pfirst && !pflag) { /* parameters must be all positioned or none */ goto done; } if (cnk->max <= 0) /* what ?? */ goto done; cnk->num = cnk->max; cnk->max = -1; ch = *format++; } else if (ch == '*') { cnk->max_star = new_chunk(); if (!cnk->max_star) /* out of memory :-( */ goto done; cnk->max_star->type = CNK_INT; if (pflag) { int num; ch = *format++; if (!isdigit((unsigned char)ch)) { /* parameters must be all positioned or none */ goto done; } for (num = 0; isdigit((unsigned char)ch); ch = *format++) { num = 10 * num + char_to_int(ch); } cnk->max_star->num = num; if (ch != '$') /* what ?? */ goto done; } else { cnk->max_star->num = ++pnum; } max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star); if (max_pos == 0) /* out of memory :-( */ goto done; ch = *format++; state = DP_S_MOD; } else { state = DP_S_MOD; } break; case DP_S_MOD: switch (ch) { case 'h': cnk->cflags = DP_C_SHORT; ch = *format++; if (ch == 'h') { cnk->cflags = DP_C_CHAR; ch = *format++; } break; case 'l': cnk->cflags = DP_C_LONG; ch = *format++; if (ch == 'l') { /* It's a long long */ cnk->cflags = DP_C_LLONG; ch = *format++; } break; case 'L': cnk->cflags = DP_C_LDOUBLE; ch = *format++; break; case 'z': cnk->cflags = DP_C_SIZET; ch = *format++; break; default: break; } state = DP_S_CONV; break; case DP_S_CONV: if (cnk->num == 0) cnk->num = ++pnum; max_pos = add_cnk_list_entry(&clist, max_pos, cnk); if (max_pos == 0) /* out of memory :-( */ goto done; switch (ch) { case 'd': case 'i': cnk->type = CNK_INT; break; case 'o': cnk->type = CNK_OCTAL; cnk->flags |= DP_F_UNSIGNED; break; case 'u': cnk->type = CNK_UINT; cnk->flags |= DP_F_UNSIGNED; break; case 'X': cnk->flags |= DP_F_UP; case 'x': cnk->type = CNK_HEX; cnk->flags |= DP_F_UNSIGNED; break; case 'A': /* hex float not supported yet */ case 'E': case 'G': case 'F': cnk->flags |= DP_F_UP; case 'a': /* hex float not supported yet */ case 'e': case 'f': case 'g': cnk->type = CNK_FLOAT; break; case 'c': cnk->type = CNK_CHAR; break; case 's': cnk->type = CNK_STRING; break; case 'p': cnk->type = CNK_PTR; cnk->flags |= DP_F_UNSIGNED; break; case 'n': cnk->type = CNK_NUM; break; case '%': cnk->type = CNK_PRCNT; break; default: /* Unknown, bail out*/ goto done; } ch = *format++; state = DP_S_DEFAULT; break; case DP_S_DONE: break; default: /* hmm? */ break; /* some picky compilers need this */ } } /* retrieve the format arguments */ for (pnum = 0; pnum < max_pos; pnum++) { int i; if (clist[pnum].num == 0) { /* ignoring a parameter should not be permitted * all parameters must be matched at least once * BUT seem some system ignore this rule ... * at least my glibc based system does --SSS */ #ifdef DEBUG_SNPRINTF printf("parameter at position %d not used\n", pnum+1); #endif /* eat the parameter */ va_arg (args, int); continue; } for (i = 1; i < clist[pnum].num; i++) { if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) { /* nooo noo no! * all the references to a parameter * must be of the same type */ goto done; } } cnk = clist[pnum].chunks[0]; switch (cnk->type) { case CNK_INT: if (cnk->cflags == DP_C_SHORT) cnk->value = va_arg (args, int); else if (cnk->cflags == DP_C_LONG) cnk->value = va_arg (args, long int); else if (cnk->cflags == DP_C_LLONG) cnk->value = va_arg (args, LLONG); else if (cnk->cflags == DP_C_SIZET) cnk->value = va_arg (args, ssize_t); else cnk->value = va_arg (args, int); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->value = cnk->value; } break; case CNK_OCTAL: case CNK_UINT: case CNK_HEX: if (cnk->cflags == DP_C_SHORT) cnk->value = va_arg (args, unsigned int); else if (cnk->cflags == DP_C_LONG) cnk->value = (unsigned long int)va_arg (args, unsigned long int); else if (cnk->cflags == DP_C_LLONG) cnk->value = (LLONG)va_arg (args, unsigned LLONG); else if (cnk->cflags == DP_C_SIZET) cnk->value = (size_t)va_arg (args, size_t); else cnk->value = (unsigned int)va_arg (args, unsigned int); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->value = cnk->value; } break; case CNK_FLOAT: if (cnk->cflags == DP_C_LDOUBLE) cnk->fvalue = va_arg (args, LDOUBLE); else cnk->fvalue = va_arg (args, double); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->fvalue = cnk->fvalue; } break; case CNK_CHAR: cnk->value = va_arg (args, int); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->value = cnk->value; } break; case CNK_STRING: cnk->strvalue = va_arg (args, char *); if (!cnk->strvalue) cnk->strvalue = "(NULL)"; for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->strvalue = cnk->strvalue; } break; case CNK_PTR: cnk->strvalue = va_arg (args, void *); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->strvalue = cnk->strvalue; } break; case CNK_NUM: if (cnk->cflags == DP_C_CHAR) cnk->pnum = va_arg (args, char *); else if (cnk->cflags == DP_C_SHORT) cnk->pnum = va_arg (args, short int *); else if (cnk->cflags == DP_C_LONG) cnk->pnum = va_arg (args, long int *); else if (cnk->cflags == DP_C_LLONG) cnk->pnum = va_arg (args, LLONG *); else if (cnk->cflags == DP_C_SIZET) cnk->pnum = va_arg (args, ssize_t *); else cnk->pnum = va_arg (args, int *); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->pnum = cnk->pnum; } break; case CNK_PRCNT: break; default: /* what ?? */ goto done; } } /* print out the actual string from chunks */ currlen = 0; cnk = chunks; while (cnk) { int len, min, max; if (cnk->min_star) min = cnk->min_star->value; else min = cnk->min; if (cnk->max_star) max = cnk->max_star->value; else max = cnk->max; switch (cnk->type) { case CNK_FMT_STR: if (maxlen != 0 && maxlen > currlen) { if (maxlen > (currlen + cnk->len)) len = cnk->len; else len = maxlen - currlen; memcpy(&(buffer[currlen]), &(base[cnk->start]), len); } currlen += cnk->len; break; case CNK_INT: case CNK_UINT: fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags); break; case CNK_OCTAL: fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags); break; case CNK_HEX: fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags); break; case CNK_FLOAT: fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags); break; case CNK_CHAR: dopr_outch (buffer, &currlen, maxlen, cnk->value); break; case CNK_STRING: if (max == -1) { max = strlen(cnk->strvalue); } fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max); break; case CNK_PTR: fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags); break; case CNK_NUM: if (cnk->cflags == DP_C_CHAR) *((char *)(cnk->pnum)) = (char)currlen; else if (cnk->cflags == DP_C_SHORT) *((short int *)(cnk->pnum)) = (short int)currlen; else if (cnk->cflags == DP_C_LONG) *((long int *)(cnk->pnum)) = (long int)currlen; else if (cnk->cflags == DP_C_LLONG) *((LLONG *)(cnk->pnum)) = (LLONG)currlen; else if (cnk->cflags == DP_C_SIZET) *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen; else *((int *)(cnk->pnum)) = (int)currlen; break; case CNK_PRCNT: dopr_outch (buffer, &currlen, maxlen, '%'); break; default: /* what ?? */ goto done; } cnk = cnk->next; } if (maxlen != 0) { if (currlen < maxlen - 1) buffer[currlen] = '\0'; else if (maxlen > 0) buffer[maxlen - 1] = '\0'; } ret = currlen; done: va_end(args); while (chunks) { cnk = chunks->next; free(chunks); chunks = cnk; } if (clist) { for (pnum = 0; pnum < max_pos; pnum++) { if (clist[pnum].chunks) free(clist[pnum].chunks); } free(clist); } return ret; } static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max) { int padlen, strln; /* amount to pad */ int cnt = 0; #ifdef DEBUG_SNPRINTF printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); #endif if (value == 0) { value = ""; } for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ padlen = min - strln; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justify */ while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --padlen; } while (*value && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, *value++); ++cnt; } while (padlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; } } /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ static void fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base, int min, int max, int flags) { int signvalue = 0; unsigned LLONG uvalue; char convert[20]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ int caps = 0; if (max < 0) max = 0; uvalue = value; if(!(flags & DP_F_UNSIGNED)) { if( value < 0 ) { signvalue = '-'; uvalue = -value; } else { if (flags & DP_F_PLUS) /* Do a sign (+/i) */ signvalue = '+'; else if (flags & DP_F_SPACE) signvalue = ' '; } } if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ do { convert[place++] = (caps? "0123456789ABCDEF":"0123456789abcdef") [uvalue % (unsigned)base ]; uvalue = (uvalue / (unsigned)base ); } while(uvalue && (place < 20)); if (place == 20) place--; convert[place] = 0; zpadlen = max - place; spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); if (zpadlen < 0) zpadlen = 0; if (spadlen < 0) spadlen = 0; if (flags & DP_F_ZERO) { zpadlen = MAX(zpadlen, spadlen); spadlen = 0; } if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */ #ifdef DEBUG_SNPRINTF printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", zpadlen, spadlen, min, max, place); #endif /* Spaces */ while (spadlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --spadlen; } /* Sign */ if (signvalue) dopr_outch (buffer, currlen, maxlen, signvalue); /* Zeros */ if (zpadlen > 0) { while (zpadlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --zpadlen; } } /* Digits */ while (place > 0) dopr_outch (buffer, currlen, maxlen, convert[--place]); /* Left Justified spaces */ while (spadlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++spadlen; } } static LDOUBLE abs_val(LDOUBLE value) { LDOUBLE result = value; if (value < 0) result = -value; return result; } static LDOUBLE POW10(int exp) { LDOUBLE result = 1; while (exp) { result *= 10; exp--; } return result; } static LLONG ROUND(LDOUBLE value) { LLONG intpart; intpart = (LLONG)value; value = value - intpart; if (value >= 0.5) intpart++; return intpart; } /* a replacement for modf that doesn't need the math library. Should be portable, but slow */ static double my_modf(double x0, double *iptr) { int i; LLONG l=0; double x = x0; double f = 1.0; for (i=0;i<100;i++) { l = (long)x; if (l <= (x+1) && l >= (x-1)) break; x *= 0.1; f *= 10.0; } if (i == 100) { /* yikes! the number is beyond what we can handle. What do we do? */ (*iptr) = 0; return 0; } if (i != 0) { double i2; double ret; ret = my_modf(x0-l*f, &i2); (*iptr) = l*f + i2; return ret; } (*iptr) = l; return x - (*iptr); } static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags) { int signvalue = 0; double ufvalue; char iconvert[311]; char fconvert[311]; int iplace = 0; int fplace = 0; int padlen = 0; /* amount to pad */ int zpadlen = 0; int caps = 0; int idx; double intpart; double fracpart; double temp; /* * AIX manpage says the default is 0, but Solaris says the default * is 6, and sprintf on AIX defaults to 6 */ if (max < 0) max = 6; ufvalue = abs_val (fvalue); if (fvalue < 0) { signvalue = '-'; } else { if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ signvalue = '+'; } else { if (flags & DP_F_SPACE) signvalue = ' '; } } #if 0 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ #endif #if 0 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ #endif /* * Sorry, we only support 9 digits past the decimal because of our * conversion method */ if (max > 9) max = 9; /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 */ temp = ufvalue; my_modf(temp, &intpart); fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); if (fracpart >= POW10(max)) { intpart++; fracpart -= POW10(max); } /* Convert integer part */ do { temp = intpart*0.1; my_modf(temp, &intpart); idx = (int) ((temp -intpart +0.05)* 10.0); /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ iconvert[iplace++] = (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; } while (intpart && (iplace < 311)); if (iplace == 311) iplace--; iconvert[iplace] = 0; /* Convert fractional part */ if (fracpart) { do { temp = fracpart*0.1; my_modf(temp, &fracpart); idx = (int) ((temp -fracpart +0.05)* 10.0); /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ fconvert[fplace++] = (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; } while(fracpart && (fplace < 311)); if (fplace == 311) fplace--; } fconvert[fplace] = 0; /* -1 for decimal point, another -1 if we are printing a sign */ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); zpadlen = max - fplace; if (zpadlen < 0) zpadlen = 0; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justifty */ if ((flags & DP_F_ZERO) && (padlen > 0)) { if (signvalue) { dopr_outch (buffer, currlen, maxlen, signvalue); --padlen; signvalue = 0; } while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --padlen; } } while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --padlen; } if (signvalue) dopr_outch (buffer, currlen, maxlen, signvalue); while (iplace > 0) dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); #ifdef DEBUG_SNPRINTF printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); #endif /* * Decimal point. This should probably use locale to find the correct * char to print out. */ if (max > 0) { dopr_outch (buffer, currlen, maxlen, '.'); while (zpadlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --zpadlen; } while (fplace > 0) dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); } while (padlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; } } static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) { if (*currlen < maxlen) { buffer[(*currlen)] = c; } (*currlen)++; } static struct pr_chunk *new_chunk(void) { struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk)); if (!new_c) return NULL; new_c->type = 0; new_c->num = 0; new_c->min = 0; new_c->min_star = NULL; new_c->max = -1; new_c->max_star = NULL; new_c->flags = 0; new_c->cflags = 0; new_c->start = 0; new_c->len = 0; new_c->value = 0; new_c->fvalue = 0; new_c->strvalue = NULL; new_c->pnum = NULL; new_c->next = NULL; return new_c; } static int add_cnk_list_entry(struct pr_chunk_x **list, int max_num, struct pr_chunk *chunk) { struct pr_chunk_x *l; struct pr_chunk **c; int max; int cnum; int i, pos; if (chunk->num > max_num) { max = chunk->num; if (*list == NULL) { l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max); pos = 0; } else { l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max); pos = max_num; } if (l == NULL) { for (i = 0; i < max; i++) { if ((*list)[i].chunks) free((*list)[i].chunks); } return 0; } for (i = pos; i < max; i++) { l[i].chunks = NULL; l[i].num = 0; } } else { l = *list; max = max_num; } i = chunk->num - 1; cnum = l[i].num + 1; if (l[i].chunks == NULL) { c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); } else { c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum); } if (c == NULL) { for (i = 0; i < max; i++) { if (l[i].chunks) free(l[i].chunks); } return 0; } c[l[i].num] = chunk; l[i].chunks = c; l[i].num = cnum; *list = l; return max; } int rep_vsnprintf (char *str, size_t count, const char *fmt, va_list args) { return dopr(str, count, fmt, args); } #endif /* yes this really must be a ||. Don't muck with this (tridge) * * The logic for these two is that we need our own definition if the * OS *either* has no definition of *sprintf, or if it does have one * that doesn't work properly according to the autoconf test. */ #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) int rep_snprintf(char *str,size_t count,const char *fmt,...) { size_t ret; va_list ap; va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap); return ret; } #endif #ifndef HAVE_C99_VSNPRINTF int rep_printf(const char *fmt, ...) { va_list ap; int ret; char *s; s = NULL; va_start(ap, fmt); ret = vasprintf(&s, fmt, ap); va_end(ap); if (s) { fwrite(s, 1, strlen(s), stdout); } free(s); return ret; } #endif #ifndef HAVE_C99_VSNPRINTF int rep_fprintf(FILE *stream, const char *fmt, ...) { va_list ap; int ret; char *s; s = NULL; va_start(ap, fmt); ret = vasprintf(&s, fmt, ap); va_end(ap); if (s) { fwrite(s, 1, strlen(s), stream); } free(s); return ret; } #endif #endif #if !defined(HAVE_VASPRINTF) || !defined(HAVE_C99_VSNPRINTF) int rep_vasprintf(char **ptr, const char *format, va_list ap) { int ret; va_list ap2; VA_COPY(ap2, ap); ret = vsnprintf(NULL, 0, format, ap2); va_end(ap2); if (ret < 0) return ret; (*ptr) = (char *)malloc(ret+1); if (!*ptr) return -1; VA_COPY(ap2, ap); ret = vsnprintf(*ptr, ret+1, format, ap2); va_end(ap2); return ret; } #endif #if !defined(HAVE_ASPRINTF) || !defined(HAVE_C99_VSNPRINTF) int rep_asprintf(char **ptr, const char *format, ...) { va_list ap; int ret; *ptr = NULL; va_start(ap, format); ret = vasprintf(ptr, format, ap); va_end(ap); return ret; } #endif #ifdef TEST_SNPRINTF int sprintf(char *str,const char *fmt,...); int printf(const char *fmt,...); int main (void) { char buf1[1024]; char buf2[1024]; char *buf3; char *fp_fmt[] = { "%1.1f", "%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f", "%+22.9f", "%+4.9f", "%01.3f", "%4f", "%3.1f", "%3.2f", "%.0f", "%f", "%-8.8f", "%-9.9f", NULL }; double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 0.9996, 1.996, 4.136, 5.030201, 0.00205, /* END LIST */ 0}; char *int_fmt[] = { "%-1.5d", "%1.5d", "%123.9d", "%5.5d", "%10.5d", "% 10.5d", "%+22.33d", "%01.3d", "%4d", "%d", NULL }; long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0}; char *str_fmt[] = { "%10.5s", "%-10.5s", "%5.10s", "%-5.10s", "%10.1s", "%0.10s", "%10.0s", "%1.10s", "%s", "%.1s", "%.10s", "%10s", NULL }; char *str_vals[] = {"hello", "a", "", "a longer string", NULL}; #ifdef HAVE_LONG_LONG char *ll_fmt[] = { "%llu", NULL }; LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0}; #endif int x, y; int fail = 0; int num = 0; int l1, l2; char *ss_fmt[] = { "%zd", "%zu", NULL }; size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0}; printf ("Testing snprintf format codes against system sprintf...\n"); for (x = 0; fp_fmt[x] ; x++) { for (y = 0; fp_nums[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", fp_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } for (x = 0; int_fmt[x] ; x++) { for (y = 0; int_nums[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); l2 = sprintf (buf2, int_fmt[x], int_nums[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", int_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } for (x = 0; str_fmt[x] ; x++) { for (y = 0; str_vals[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); l2 = sprintf (buf2, str_fmt[x], str_vals[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", str_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } #ifdef HAVE_LONG_LONG for (x = 0; ll_fmt[x] ; x++) { for (y = 0; ll_nums[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]); l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", ll_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } #endif #define BUFSZ 2048 buf1[0] = buf2[0] = '\0'; if ((buf3 = malloc(BUFSZ)) == NULL) { fail++; } else { num++; memset(buf3, 'a', BUFSZ); snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3); buf1[1023] = '\0'; if (strcmp(buf1, "a") != 0) { printf("length limit buf1 '%s' expected 'a'\n", buf1); fail++; } } buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); buf1[1023] = buf2[1023] = '\0'; if (strcmp(buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); fail++; } buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); buf1[1023] = buf2[1023] = '\0'; if (strcmp(buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); fail++; } for (x = 0; ss_fmt[x] ; x++) { for (y = 0; ss_nums[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]); l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", ss_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } #if 0 buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890); l2 = sprintf(buf2, "%lld", (LLONG)1234567890); buf1[1023] = buf2[1023] = '\0'; if (strcmp(buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", "%lld", l1, buf1, l2, buf2); fail++; } buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123); l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123); buf1[1023] = buf2[1023] = '\0'; if (strcmp(buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", "%Lf", l1, buf1, l2, buf2); fail++; } #endif printf ("%d tests failed out of %d.\n", fail, num); printf("seeing how many digits we support\n"); { double v0 = 0.12345678901234567890123456789012345678901; for (x=0; x<100; x++) { double p = pow(10, x); double r = v0*p; snprintf(buf1, sizeof(buf1), "%1.1f", r); sprintf(buf2, "%1.1f", r); if (strcmp(buf1, buf2)) { printf("we seem to support %d digits\n", x-1); break; } } } return 0; } #endif /* TEST_SNPRINTF */ ctdb-2.5.1.dfsg/lib/replace/win32.m40000644000175000017500000000105212245023514016610 0ustar mathieumathieuAC_CHECK_HEADERS(direct.h windows.h winsock2.h ws2tcpip.h) ####################################### # Check for mkdir mode AC_CACHE_CHECK( [whether mkdir supports mode], libreplace_cv_mkdir_has_mode, AC_TRY_COMPILE([ #include #ifdef HAVE_DIRECT_H #include #endif],[ mkdir("foo",0777); return 0; ], libreplace_cv_mkdir_has_mode="yes", libreplace_cv_mkdir_has_mode="no") ) if test "$libreplace_cv_mkdir_has_mode" = "yes" then AC_DEFINE(HAVE_MKDIR_MODE, 1, [Define if target mkdir supports mode option]) fi ctdb-2.5.1.dfsg/lib/replace/system/0000755000175000017500000000000012245023514016732 5ustar mathieumathieuctdb-2.5.1.dfsg/lib/replace/system/README0000644000175000017500000000036212245023514017613 0ustar mathieumathieuThis directory contains wrappers around logical groups of system include files. The idea is to avoid #ifdef blocks in the main code, and instead put all the necessary conditional includes in subsystem specific header files in this directory. ctdb-2.5.1.dfsg/lib/replace/system/syslog.h0000644000175000017500000000343512245023514020430 0ustar mathieumathieu#ifndef _system_syslog_h #define _system_syslog_h /* Unix SMB/CIFS implementation. syslog system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_SYSLOG_H #include #else #ifdef HAVE_SYS_SYSLOG_H #include #endif #endif /* For sys_adminlog(). */ #ifndef LOG_EMERG #define LOG_EMERG 0 /* system is unusable */ #endif #ifndef LOG_ALERT #define LOG_ALERT 1 /* action must be taken immediately */ #endif #ifndef LOG_CRIT #define LOG_CRIT 2 /* critical conditions */ #endif #ifndef LOG_ERR #define LOG_ERR 3 /* error conditions */ #endif #ifndef LOG_WARNING #define LOG_WARNING 4 /* warning conditions */ #endif #ifndef LOG_NOTICE #define LOG_NOTICE 5 /* normal but significant condition */ #endif #ifndef LOG_INFO #define LOG_INFO 6 /* informational */ #endif #ifndef LOG_DEBUG #define LOG_DEBUG 7 /* debug-level messages */ #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/shmem.h0000644000175000017500000000262512245023514020221 0ustar mathieumathieu#ifndef _system_shmem_h #define _system_shmem_h /* Unix SMB/CIFS implementation. shared memory system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #if defined(HAVE_SYS_IPC_H) #include #endif /* HAVE_SYS_IPC_H */ #if defined(HAVE_SYS_SHM_H) #include #endif /* HAVE_SYS_SHM_H */ #ifdef HAVE_SYS_MMAN_H #include #endif /* NetBSD doesn't have these */ #ifndef SHM_R #define SHM_R 0400 #endif #ifndef SHM_W #define SHM_W 0200 #endif #ifndef MAP_FILE #define MAP_FILE 0 #endif #ifndef MAP_FAILED #define MAP_FAILED ((void *)-1) #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/select.h0000644000175000017500000000453612245023514020372 0ustar mathieumathieu#ifndef _system_select_h #define _system_select_h /* Unix SMB/CIFS implementation. select system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_EPOLL_H #include #endif #ifndef SELECT_CAST #define SELECT_CAST #endif #ifdef HAVE_POLL #include #else /* Type used for the number of file descriptors. */ typedef unsigned long int nfds_t; /* Data structure describing a polling request. */ struct pollfd { int fd; /* File descriptor to poll. */ short int events; /* Types of events poller cares about. */ short int revents; /* Types of events that actually occurred. */ }; /* Event types that can be polled for. These bits may be set in `events' to indicate the interesting event types; they will appear in `revents' to indicate the status of the file descriptor. */ #define POLLIN 0x001 /* There is data to read. */ #define POLLPRI 0x002 /* There is urgent data to read. */ #define POLLOUT 0x004 /* Writing now will not block. */ #define POLLRDNORM 0x040 /* Normal data may be read. */ #define POLLRDBAND 0x080 /* Priority data may be read. */ #define POLLWRNORM 0x100 /* Writing now will not block. */ #define POLLWRBAND 0x200 /* Priority data may be written. */ #define POLLERR 0x008 /* Error condition. */ #define POLLHUP 0x010 /* Hung up. */ #define POLLNVAL 0x020 /* Invalid polling request. */ /* define is in "replace.h" */ int rep_poll(struct pollfd *fds, nfds_t nfds, int timeout); #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/dir.h0000644000175000017500000000344012245023514017662 0ustar mathieumathieu#ifndef _system_dir_h #define _system_dir_h /* Unix SMB/CIFS implementation. directory system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #if HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif #endif #ifndef HAVE_MKDIR_MODE #define mkdir(dir, mode) mkdir(dir) #endif /* Test whether a file name is the "." or ".." directory entries. * These really should be inline functions. */ #ifndef ISDOT #define ISDOT(path) ( \ *((const char *)(path)) == '.' && \ *(((const char *)(path)) + 1) == '\0' \ ) #endif #ifndef ISDOTDOT #define ISDOTDOT(path) ( \ *((const char *)(path)) == '.' && \ *(((const char *)(path)) + 1) == '.' && \ *(((const char *)(path)) + 2) == '\0' \ ) #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/time.h0000644000175000017500000000446112245023514020046 0ustar mathieumathieu#ifndef _system_time_h #define _system_time_h /* Unix SMB/CIFS implementation. time system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif #endif #ifdef HAVE_UTIME_H #include #else struct utimbuf { time_t actime; /* access time */ time_t modtime; /* modification time */ }; #endif #ifndef HAVE_STRUCT_TIMESPEC struct timespec { time_t tv_sec; /* Seconds. */ long tv_nsec; /* Nanoseconds. */ }; #endif #ifndef HAVE_MKTIME /* define is in "replace.h" */ time_t rep_mktime(struct tm *t); #endif #ifndef HAVE_TIMEGM /* define is in "replace.h" */ time_t rep_timegm(struct tm *tm); #endif #ifndef HAVE_UTIME /* define is in "replace.h" */ int rep_utime(const char *filename, const struct utimbuf *buf); #endif #ifndef HAVE_UTIMES /* define is in "replace.h" */ int rep_utimes(const char *filename, const struct timeval tv[2]); #endif #ifndef HAVE_CLOCK_GETTIME /* CLOCK_REALTIME is required by POSIX */ #define CLOCK_REALTIME 0 typedef int clockid_t; int rep_clock_gettime(clockid_t clk_id, struct timespec *tp); #endif /* make sure we have a best effort CUSTOM_CLOCK_MONOTONIC we can rely on */ #if defined(CLOCK_MONOTONIC) #define CUSTOM_CLOCK_MONOTONIC CLOCK_MONOTONIC #elif defined(CLOCK_HIGHRES) #define CUSTOM_CLOCK_MONOTONIC CLOCK_HIGHRES #else #define CUSTOM_CLOCK_MONOTONIC CLOCK_REALTIME #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/config.m40000644000175000017500000000750212245023514020445 0ustar mathieumathieu# filesys AC_HEADER_DIRENT AC_CHECK_HEADERS(fcntl.h sys/fcntl.h sys/resource.h sys/ioctl.h sys/mode.h sys/filio.h sys/fs/s5param.h sys/filsys.h) AC_CHECK_HEADERS(sys/acl.h acl/libacl.h sys/file.h) # select AC_CHECK_HEADERS(sys/select.h) # poll AC_CHECK_HEADERS(poll.h) AC_CHECK_FUNCS(poll,[],[LIBREPLACEOBJ="${LIBREPLACEOBJ} $libreplacedir/poll.o"]) # time AC_CHECK_HEADERS(sys/time.h utime.h) AC_HEADER_TIME AC_CHECK_FUNCS(utime utimes) AC_CACHE_CHECK([if gettimeofday takes TZ argument],libreplace_cv_HAVE_GETTIMEOFDAY_TZ,[ AC_TRY_RUN([ #include #include main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}], libreplace_cv_HAVE_GETTIMEOFDAY_TZ=yes,libreplace_cv_HAVE_GETTIMEOFDAY_TZ=no,libreplace_cv_HAVE_GETTIMEOFDAY_TZ=yes)]) if test x"$libreplace_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then AC_DEFINE(HAVE_GETTIMEOFDAY_TZ,1,[Whether gettimeofday() is available]) fi # wait AC_HEADER_SYS_WAIT # capability AC_CHECK_HEADERS(sys/capability.h) case "$host_os" in *linux*) AC_CACHE_CHECK([for broken RedHat 7.2 system header files],libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS,[ AC_TRY_COMPILE([ #ifdef HAVE_SYS_VFS_H #include #endif #ifdef HAVE_SYS_CAPABILITY_H #include #endif ],[ int i; ], libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=no, libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS=yes )]) if test x"$libreplace_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS" = x"yes"; then AC_DEFINE(BROKEN_REDHAT_7_SYSTEM_HEADERS,1,[Broken RedHat 7.2 system header files]) fi AC_CACHE_CHECK([for broken RHEL5 sys/capability.h],libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER,[ AC_TRY_COMPILE([ #ifdef HAVE_SYS_CAPABILITY_H #include #endif #include ],[ __s8 i; ], libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER=no, libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER=yes )]) if test x"$libreplace_cv_BROKEN_RHEL5_SYS_CAP_HEADER" = x"yes"; then AC_DEFINE(BROKEN_RHEL5_SYS_CAP_HEADER,1,[Broken RHEL5 sys/capability.h]) fi ;; esac # passwd AC_CHECK_HEADERS(grp.h sys/id.h compat.h shadow.h sys/priv.h pwd.h sys/security.h) AC_CHECK_FUNCS(getpwnam_r getpwuid_r getpwent_r) AC_HAVE_DECL(getpwent_r, [ #include #include ]) AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)], [ #ifndef HAVE_GETPWENT_R_DECL #error missing getpwent_r prototype #endif return NULL; ],[ AC_DEFINE(SOLARIS_GETPWENT_R, 1, [getpwent_r solaris function prototype]) ],[],[ #include #include ]) AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf, size_t buflen)], [ #ifndef HAVE_GETPWENT_R_DECL #error missing getpwent_r prototype #endif return NULL; ],[ AC_DEFINE(SOLARIS_GETPWENT_R, 1, [getpwent_r irix (similar to solaris) function prototype]) ],[],[ #include #include ]) AC_CHECK_FUNCS(getgrnam_r getgrgid_r getgrent_r) AC_HAVE_DECL(getgrent_r, [ #include #include ]) AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, int buflen)], [ #ifndef HAVE_GETGRENT_R_DECL #error missing getgrent_r prototype #endif return NULL; ],[ AC_DEFINE(SOLARIS_GETGRENT_R, 1, [getgrent_r solaris function prototype]) ],[],[ #include #include ]) AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, size_t buflen)], [ #ifndef HAVE_GETGRENT_R_DECL #error missing getgrent_r prototype #endif return NULL; ],[ AC_DEFINE(SOLARIS_GETGRENT_R, 1, [getgrent_r irix (similar to solaris) function prototype]) ],[],[ #include #include ]) AC_CHECK_FUNCS(getgrouplist) # locale AC_CHECK_HEADERS(ctype.h locale.h langinfo.h) # glob AC_CHECK_HEADERS(fnmatch.h) # shmem AC_CHECK_HEADERS(sys/ipc.h sys/mman.h sys/shm.h ) # terminal AC_CHECK_HEADERS(termios.h termio.h sys/termio.h ) ctdb-2.5.1.dfsg/lib/replace/system/kerberos.h0000644000175000017500000000213112245023514020714 0ustar mathieumathieu#ifndef _system_kerberos_h #define _system_kerberos_h /* Unix SMB/CIFS implementation. kerberos system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_KRB5 #if HAVE_KRB5_H #include #endif #if HAVE_COM_ERR_H #include #endif #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/wait.h0000644000175000017500000000257112245023514020054 0ustar mathieumathieu#ifndef _system_wait_h #define _system_wait_h /* Unix SMB/CIFS implementation. waitpid system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_SYS_WAIT_H #include #endif #include #ifndef SIGCLD #define SIGCLD SIGCHLD #endif #ifdef HAVE_SETJMP_H #include #endif #ifdef HAVE_SYS_UCONTEXT_H #include #endif #if !defined(HAVE_SIG_ATOMIC_T_TYPE) typedef int sig_atomic_t; #endif #if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4) int rep_waitpid(pid_t pid,int *status,int options) #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/glob.h0000644000175000017500000000207712245023514020034 0ustar mathieumathieu#ifndef _system_glob_h #define _system_glob_h /* Unix SMB/CIFS implementation. glob system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_GLOB_H #include #endif #ifdef HAVE_FNMATCH_H #include #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/wscript_configure0000644000175000017500000000230312245023514022407 0ustar mathieumathieu#!/usr/bin/env python conf.CHECK_HEADERS('sys/capability.h') conf.CHECK_FUNCS('getpwnam_r getpwuid_r getpwent_r') # solaris varients of getXXent_r conf.CHECK_C_PROTOTYPE('getpwent_r', 'struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)', define='SOLARIS_GETPWENT_R', headers='pwd.h') conf.CHECK_C_PROTOTYPE('getgrent_r', 'struct group *getgrent_r(struct group *src, char *buf, int buflen)', define='SOLARIS_GETGRENT_R', headers='grp.h') # the irix varients conf.CHECK_C_PROTOTYPE('getpwent_r', 'struct passwd *getpwent_r(struct passwd *src, char *buf, size_t buflen)', define='SOLARIS_GETPWENT_R', headers='pwd.h') conf.CHECK_C_PROTOTYPE('getgrent_r', 'struct group *getgrent_r(struct group *src, char *buf, size_t buflen)', define='SOLARIS_GETGRENT_R', headers='grp.h') conf.CHECK_FUNCS('getgrouplist') conf.CHECK_HEADERS('ctype.h locale.h langinfo.h') conf.CHECK_HEADERS('fnmatch.h locale.h langinfo.h') conf.CHECK_HEADERS('sys/ipc.h sys/mman.h sys/shm.h') conf.CHECK_HEADERS('termios.h termio.h sys/termio.h') ctdb-2.5.1.dfsg/lib/replace/system/readline.h0000644000175000017500000000321312245023514020665 0ustar mathieumathieu#ifndef _system_readline_h #define _system_readline_h /* Unix SMB/CIFS implementation. Readline wrappers ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_LIBREADLINE # ifdef HAVE_READLINE_READLINE_H # include # ifdef HAVE_READLINE_HISTORY_H # include # endif # else # ifdef HAVE_READLINE_H # include # ifdef HAVE_HISTORY_H # include # endif # else # undef HAVE_LIBREADLINE # endif # endif #endif #ifdef HAVE_NEW_LIBREADLINE #ifdef HAVE_CPPFUNCTION # define RL_COMPLETION_CAST (CPPFunction *) #elif HAVE_RL_COMPLETION_T # define RL_COMPLETION_CAST (rl_completion_t *) #else # define RL_COMPLETION_CAST #endif #else /* This type is missing from libreadline<4.0 (approximately) */ # define RL_COMPLETION_CAST #endif /* HAVE_NEW_LIBREADLINE */ #endif ctdb-2.5.1.dfsg/lib/replace/system/terminal.h0000644000175000017500000000262512245023514020723 0ustar mathieumathieu#ifndef _system_terminal_h #define _system_terminal_h /* Unix SMB/CIFS implementation. terminal system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef SUNOS4 /* on SUNOS4 termios.h conflicts with sys/ioctl.h */ #undef HAVE_TERMIOS_H #endif #if defined(HAVE_TERMIOS_H) /* POSIX terminal handling. */ #include #elif defined(HAVE_TERMIO_H) /* Older SYSV terminal handling - don't use if we can avoid it. */ #include #elif defined(HAVE_SYS_TERMIO_H) /* Older SYSV terminal handling - don't use if we can avoid it. */ #include #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/gssapi.h0000644000175000017500000000265312245023514020377 0ustar mathieumathieu#ifndef _system_gssapi_h #define _system_gssapi_h /* Unix SMB/CIFS implementation. GSSAPI system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_GSSAPI #ifdef HAVE_GSSAPI_GSSAPI_EXT_H #include #elif HAVE_GSSAPI_GSSAPI_H #include #elif HAVE_GSSAPI_GSSAPI_GENERIC_H #include #elif HAVE_GSSAPI_H #include #endif #if HAVE_GSSAPI_GSSAPI_KRB5_H #include #endif #if HAVE_GSSAPI_GSSAPI_SPNEGO_H #include #elif HAVE_GSSAPI_SPNEGO_H #include #endif #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/locale.h0000644000175000017500000000216412245023514020345 0ustar mathieumathieu#ifndef _system_locale_h #define _system_locale_h /* Unix SMB/CIFS implementation. locale include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_CTYPE_H #include #endif #ifdef HAVE_LOCALE_H #include #endif #ifdef HAVE_LANGINFO_H #include #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/filesys.h0000644000175000017500000001530412245023514020564 0ustar mathieumathieu#ifndef _system_filesys_h #define _system_filesys_h /* Unix SMB/CIFS implementation. filesystem system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include #include #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #ifdef HAVE_MNTENT_H #include #endif #ifdef HAVE_SYS_VFS_H #include #endif #ifdef HAVE_SYS_ACL_H #include #endif #ifdef HAVE_ACL_LIBACL_H #include #endif #ifdef HAVE_SYS_FS_S5PARAM_H #include #endif #if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY) #include #endif #ifdef HAVE_SYS_STATFS_H # include #endif #ifdef HAVE_DUSTAT_H #include #endif #ifdef HAVE_SYS_STATVFS_H #include #endif #ifdef HAVE_SYS_FILIO_H #include #endif #ifdef HAVE_SYS_FILE_H #include #endif #ifdef HAVE_FCNTL_H #include #else #ifdef HAVE_SYS_FCNTL_H #include #endif #endif #ifdef HAVE_SYS_MODE_H /* apparently AIX needs this for S_ISLNK */ #ifndef S_ISLNK #include #endif #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif /* * Veritas File System. Often in addition to native. * Quotas different. */ #if defined(HAVE_SYS_FS_VX_QUOTA_H) #define VXFS_QUOTA #endif #if HAVE_SYS_ATTRIBUTES_H #include #elif HAVE_ATTR_ATTRIBUTES_H #include #endif /* mutually exclusive (SuSE 8.2) */ #if HAVE_ATTR_XATTR_H #include #elif HAVE_SYS_XATTR_H #include #endif #ifdef HAVE_SYS_EA_H #include #endif #ifdef HAVE_SYS_EXTATTR_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifndef XATTR_CREATE #define XATTR_CREATE 0x1 /* set value, fail if attr already exists */ #endif #ifndef XATTR_REPLACE #define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */ #endif /* Some POSIX definitions for those without */ #ifndef S_IFDIR #define S_IFDIR 0x4000 #endif #ifndef S_ISDIR #define S_ISDIR(mode) ((mode & 0xF000) == S_IFDIR) #endif #ifndef S_IRWXU #define S_IRWXU 00700 /* read, write, execute: owner */ #endif #ifndef S_IRUSR #define S_IRUSR 00400 /* read permission: owner */ #endif #ifndef S_IWUSR #define S_IWUSR 00200 /* write permission: owner */ #endif #ifndef S_IXUSR #define S_IXUSR 00100 /* execute permission: owner */ #endif #ifndef S_IRWXG #define S_IRWXG 00070 /* read, write, execute: group */ #endif #ifndef S_IRGRP #define S_IRGRP 00040 /* read permission: group */ #endif #ifndef S_IWGRP #define S_IWGRP 00020 /* write permission: group */ #endif #ifndef S_IXGRP #define S_IXGRP 00010 /* execute permission: group */ #endif #ifndef S_IRWXO #define S_IRWXO 00007 /* read, write, execute: other */ #endif #ifndef S_IROTH #define S_IROTH 00004 /* read permission: other */ #endif #ifndef S_IWOTH #define S_IWOTH 00002 /* write permission: other */ #endif #ifndef S_IXOTH #define S_IXOTH 00001 /* execute permission: other */ #endif #ifndef O_ACCMODE #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) #endif #ifndef MAXPATHLEN #define MAXPATHLEN 256 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifdef _WIN32 #define mkdir(d,m) _mkdir(d) #endif #ifdef UID_WRAPPER # ifndef UID_WRAPPER_DISABLE # ifndef UID_WRAPPER_NOT_REPLACE # define UID_WRAPPER_REPLACE # endif /* UID_WRAPPER_NOT_REPLACE */ # include "../uid_wrapper/uid_wrapper.h" # endif /* UID_WRAPPER_DISABLE */ #else /* UID_WRAPPER */ # define uwrap_enabled() 0 #endif /* UID_WRAPPER */ /* this allows us to use a uniform error handling for our xattr wrappers */ #ifndef ENOATTR #define ENOATTR ENODATA #endif #if !defined(HAVE_GETXATTR) || defined(XATTR_ADDITIONAL_OPTIONS) ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size); #define getxattr(path, name, value, size) rep_getxattr(path, name, value, size) /* define is in "replace.h" */ #endif #if !defined(HAVE_FGETXATTR) || defined(XATTR_ADDITIONAL_OPTIONS) ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size); #define fgetxattr(filedes, name, value, size) rep_fgetxattr(filedes, name, value, size) /* define is in "replace.h" */ #endif #if !defined(HAVE_LISTXATTR) || defined(XATTR_ADDITIONAL_OPTIONS) ssize_t rep_listxattr (const char *path, char *list, size_t size); #define listxattr(path, list, size) rep_listxattr(path, list, size) /* define is in "replace.h" */ #endif #if !defined(HAVE_FLISTXATTR) || defined(XATTR_ADDITIONAL_OPTIONS) ssize_t rep_flistxattr (int filedes, char *list, size_t size); #define flistxattr(filedes, value, size) rep_flistxattr(filedes, value, size) /* define is in "replace.h" */ #endif #if !defined(HAVE_REMOVEXATTR) || defined(XATTR_ADDITIONAL_OPTIONS) int rep_removexattr (const char *path, const char *name); #define removexattr(path, name) rep_removexattr(path, name) /* define is in "replace.h" */ #endif #if !defined(HAVE_FREMOVEXATTR) || defined(XATTR_ADDITIONAL_OPTIONS) int rep_fremovexattr (int filedes, const char *name); #define fremovexattr(filedes, name) rep_fremovexattr(filedes, name) /* define is in "replace.h" */ #endif #if !defined(HAVE_SETXATTR) || defined(XATTR_ADDITIONAL_OPTIONS) int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags); #define setxattr(path, name, value, size, flags) rep_setxattr(path, name, value, size, flags) /* define is in "replace.h" */ #endif #if !defined(HAVE_FSETXATTR) || defined(XATTR_ADDITIONAL_OPTIONS) int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags); #define fsetxattr(filedes, name, value, size, flags) rep_fsetxattr(filedes, name, value, size, flags) /* define is in "replace.h" */ #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/network.h0000644000175000017500000002025112245023514020574 0ustar mathieumathieu#ifndef _system_network_h #define _system_network_h /* Unix SMB/CIFS implementation. networking system include wrappers Copyright (C) Andrew Tridgell 2004 Copyright (C) Jelmer Vernooij 2007 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifndef LIBREPLACE_NETWORK_CHECKS #error "AC_LIBREPLACE_NETWORK_CHECKS missing in configure" #endif #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_UNIXSOCKET #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif /* * The next three defines are needed to access the IPTOS_* options * on some systems. */ #ifdef HAVE_NETINET_IN_SYSTM_H #include #endif #ifdef HAVE_NETINET_IN_IP_H #include #endif #ifdef HAVE_NETINET_IP_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_UIO_H #include #endif #ifdef HAVE_STROPTS_H #include #endif #ifndef HAVE_SOCKLEN_T #define HAVE_SOCKLEN_T typedef int socklen_t; #endif #if !defined (HAVE_INET_NTOA) || defined(REPLACE_INET_NTOA) /* define is in "replace.h" */ char *rep_inet_ntoa(struct in_addr ip); #endif #ifndef HAVE_INET_PTON /* define is in "replace.h" */ int rep_inet_pton(int af, const char *src, void *dst); #endif #ifndef HAVE_INET_NTOP /* define is in "replace.h" */ const char *rep_inet_ntop(int af, const void *src, char *dst, socklen_t size); #endif #ifndef HAVE_INET_ATON /* define is in "replace.h" */ int rep_inet_aton(const char *src, struct in_addr *dst); #endif #ifndef HAVE_CONNECT /* define is in "replace.h" */ int rep_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); #endif #ifndef HAVE_GETHOSTBYNAME /* define is in "replace.h" */ struct hostent *rep_gethostbyname(const char *name); #endif #ifdef HAVE_IFADDRS_H #include #endif #ifndef HAVE_STRUCT_IFADDRS struct ifaddrs { struct ifaddrs *ifa_next; /* Pointer to next struct */ char *ifa_name; /* Interface name */ unsigned int ifa_flags; /* Interface flags */ struct sockaddr *ifa_addr; /* Interface address */ struct sockaddr *ifa_netmask; /* Interface netmask */ #undef ifa_dstaddr struct sockaddr *ifa_dstaddr; /* P2P interface destination */ void *ifa_data; /* Address specific data */ }; #endif #ifndef HAVE_GETIFADDRS int rep_getifaddrs(struct ifaddrs **); #endif #ifndef HAVE_FREEIFADDRS void rep_freeifaddrs(struct ifaddrs *); #endif #ifndef HAVE_SOCKETPAIR /* define is in "replace.h" */ int rep_socketpair(int d, int type, int protocol, int sv[2]); #endif /* * Some systems have getaddrinfo but not the * defines needed to use it. */ /* Various macros that ought to be in , but might not be */ #ifndef EAI_FAIL #define EAI_BADFLAGS (-1) #define EAI_NONAME (-2) #define EAI_AGAIN (-3) #define EAI_FAIL (-4) #define EAI_FAMILY (-6) #define EAI_SOCKTYPE (-7) #define EAI_SERVICE (-8) #define EAI_MEMORY (-10) #define EAI_SYSTEM (-11) #endif /* !EAI_FAIL */ #ifndef AI_PASSIVE #define AI_PASSIVE 0x0001 #endif #ifndef AI_CANONNAME #define AI_CANONNAME 0x0002 #endif #ifndef AI_NUMERICHOST /* * some platforms don't support AI_NUMERICHOST; define as zero if using * the system version of getaddrinfo... */ #if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) #define AI_NUMERICHOST 0 #else #define AI_NUMERICHOST 0x0004 #endif #endif /* * Some of the functions in source3/lib/util_sock.c use AI_ADDRCONFIG. On QNX * 6.3.0, this macro is defined but, if it's used, getaddrinfo will fail. This * prevents smbd from opening any sockets. * * If I undefine AI_ADDRCONFIG on such systems and define it to be 0, * this works around the issue. */ #ifdef __QNX__ #include #if _NTO_VERSION == 630 #undef AI_ADDRCONFIG #endif #endif #ifndef AI_ADDRCONFIG /* * logic copied from AI_NUMERICHOST */ #if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) #define AI_ADDRCONFIG 0 #else #define AI_ADDRCONFIG 0x0020 #endif #endif #ifndef AI_NUMERICSERV /* * logic copied from AI_NUMERICHOST */ #if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) #define AI_NUMERICSERV 0 #else #define AI_NUMERICSERV 0x0400 #endif #endif #ifndef NI_NUMERICHOST #define NI_NUMERICHOST 1 #endif #ifndef NI_NUMERICSERV #define NI_NUMERICSERV 2 #endif #ifndef NI_NOFQDN #define NI_NOFQDN 4 #endif #ifndef NI_NAMEREQD #define NI_NAMEREQD 8 #endif #ifndef NI_DGRAM #define NI_DGRAM 16 #endif #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endif #ifndef NI_MAXSERV #define NI_MAXSERV 32 #endif /* * glibc on linux doesn't seem to have MSG_WAITALL * defined. I think the kernel has it though.. */ #ifndef MSG_WAITALL #define MSG_WAITALL 0 #endif #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 #endif #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif #ifndef EAFNOSUPPORT #define EAFNOSUPPORT EINVAL #endif #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 #endif #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 255 #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN HOST_NAME_MAX #endif #ifndef HAVE_SA_FAMILY_T #define HAVE_SA_FAMILY_T typedef unsigned short int sa_family_t; #endif #ifndef HAVE_STRUCT_SOCKADDR_STORAGE #define HAVE_STRUCT_SOCKADDR_STORAGE #ifdef HAVE_STRUCT_SOCKADDR_IN6 #define sockaddr_storage sockaddr_in6 #define ss_family sin6_family #define HAVE_SS_FAMILY 1 #else /*HAVE_STRUCT_SOCKADDR_IN6*/ #define sockaddr_storage sockaddr_in #define ss_family sin_family #define HAVE_SS_FAMILY 1 #endif /*HAVE_STRUCT_SOCKADDR_IN6*/ #endif /*HAVE_STRUCT_SOCKADDR_STORAGE*/ #ifndef HAVE_SS_FAMILY #ifdef HAVE___SS_FAMILY #define ss_family __ss_family #define HAVE_SS_FAMILY 1 #endif #endif #ifndef IOV_MAX # ifdef UIO_MAXIOV # define IOV_MAX UIO_MAXIOV # else # ifdef __sgi /* * IRIX 6.5 has sysconf(_SC_IOV_MAX) * which might return 512 or bigger */ # define IOV_MAX 512 # endif # endif #endif #ifndef HAVE_STRUCT_ADDRINFO #define HAVE_STRUCT_ADDRINFO struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; }; #endif /* HAVE_STRUCT_ADDRINFO */ #if !defined(HAVE_GETADDRINFO) #include "getaddrinfo.h" #endif /* Needed for some systems that don't define it (Solaris). */ #ifndef ifr_netmask #define ifr_netmask ifr_addr #endif /* Some old Linux systems have broken header files */ #ifdef HAVE_IPV6 #ifdef HAVE_LINUX_IPV6_V6ONLY_26 #define IPV6_V6ONLY 26 #endif /* HAVE_LINUX_IPV6_V6ONLY_26 */ #endif /* HAVE_IPV6 */ #ifdef SOCKET_WRAPPER #ifndef SOCKET_WRAPPER_DISABLE #ifndef SOCKET_WRAPPER_NOT_REPLACE #define SOCKET_WRAPPER_REPLACE #endif /* SOCKET_WRAPPER_NOT_REPLACE */ #include "../socket_wrapper/socket_wrapper.h" #endif /* SOCKET_WRAPPER_DISABLE */ #endif /* SOCKET_WRAPPER */ #ifdef UID_WRAPPER # ifndef UID_WRAPPER_DISABLE # ifndef UID_WRAPPER_NOT_REPLACE # define UID_WRAPPER_REPLACE # endif /* UID_WRAPPER_NOT_REPLACE */ # include "../uid_wrapper/uid_wrapper.h" # endif /* UID_WRAPPER_DISABLE */ #else /* UID_WRAPPER */ # define uwrap_enabled() 0 #endif /* UID_WRAPPER */ #endif ctdb-2.5.1.dfsg/lib/replace/system/aio.h0000644000175000017500000000201412245023514017650 0ustar mathieumathieu#ifndef _system_aio_h #define _system_aio_h /* Unix SMB/CIFS implementation. AIO system include wrappers Copyright (C) Andrew Tridgell 2006 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_LIBAIO_H #include #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/iconv.h0000644000175000017500000000304612245023514020224 0ustar mathieumathieu#ifndef _system_iconv_h #define _system_iconv_h /* Unix SMB/CIFS implementation. iconv memory system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #if !defined(HAVE_ICONV) && defined(HAVE_ICONV_H) #define HAVE_ICONV #endif #if !defined(HAVE_GICONV) && defined(HAVE_GICONV_H) #define HAVE_GICONV #endif #if !defined(HAVE_BICONV) && defined(HAVE_BICONV_H) #define HAVE_BICONV #endif #ifdef HAVE_NATIVE_ICONV #if defined(HAVE_ICONV) #include #elif defined(HAVE_GICONV) #include #elif defined(HAVE_BICONV) #include #endif #endif /* HAVE_NATIVE_ICONV */ /* needed for some systems without iconv. Doesn't really matter what error code we use */ #ifndef EILSEQ #define EILSEQ EIO #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/capability.h0000644000175000017500000000316012245023514021224 0ustar mathieumathieu#ifndef _system_capability_h #define _system_capability_h /* Unix SMB/CIFS implementation. capability system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_SYS_CAPABILITY_H #if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H) && !defined(_PPC_STATFS_H) #define _I386_STATFS_H #define _PPC_STATFS_H #define BROKEN_REDHAT_7_STATFS_WORKAROUND #endif #if defined(BROKEN_RHEL5_SYS_CAP_HEADER) && !defined(_LINUX_TYPES_H) #define BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND #endif #include #ifdef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND #undef _LINUX_TYPES_H #undef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND #endif #ifdef BROKEN_REDHAT_7_STATFS_WORKAROUND #undef _PPC_STATFS_H #undef _I386_STATFS_H #undef BROKEN_REDHAT_7_STATFS_WORKAROUND #endif #endif #endif ctdb-2.5.1.dfsg/lib/replace/system/passwd.h0000644000175000017500000000531712245023514020412 0ustar mathieumathieu#ifndef _system_passwd_h #define _system_passwd_h /* Unix SMB/CIFS implementation. passwd system include wrappers Copyright (C) Andrew Tridgell 2004 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ /* this needs to be included before nss_wrapper.h on some systems */ #include #ifdef HAVE_PWD_H #include #endif #ifdef HAVE_GRP_H #include #endif #ifdef HAVE_SYS_PRIV_H #include #endif #ifdef HAVE_SYS_ID_H #include #endif #ifdef HAVE_CRYPT_H #include #endif #ifdef HAVE_SHADOW_H #include #endif #ifdef HAVE_SYS_SECURITY_H #include #include #define PASSWORD_LENGTH 16 #endif /* HAVE_SYS_SECURITY_H */ #ifdef HAVE_GETPWANAM #include #include #include #endif #ifdef HAVE_COMPAT_H #include #endif #ifndef NGROUPS_MAX #define NGROUPS_MAX 32 /* Guess... */ #endif /* what is the longest significant password available on your system? Knowing this speeds up password searches a lot */ #ifndef PASSWORD_LENGTH #define PASSWORD_LENGTH 8 #endif #if defined(HAVE_PUTPRPWNAM) && defined(AUTH_CLEARTEXT_SEG_CHARS) #define OSF1_ENH_SEC 1 #endif #ifndef ALLOW_CHANGE_PASSWORD #if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID)) #define ALLOW_CHANGE_PASSWORD 1 #endif #endif #if defined(HAVE_CRYPT16) && defined(HAVE_GETAUTHUID) #define ULTRIX_AUTH 1 #endif #ifdef NSS_WRAPPER #ifndef NSS_WRAPPER_DISABLE #ifndef NSS_WRAPPER_NOT_REPLACE #define NSS_WRAPPER_REPLACE #endif /* NSS_WRAPPER_NOT_REPLACE */ #include "../nss_wrapper/nss_wrapper.h" #endif /* NSS_WRAPPER_DISABLE */ #endif /* NSS_WRAPPER */ #ifdef UID_WRAPPER # ifndef UID_WRAPPER_DISABLE # ifndef UID_WRAPPER_NOT_REPLACE # define UID_WRAPPER_REPLACE # endif /* UID_WRAPPER_NOT_REPLACE */ # include "../uid_wrapper/uid_wrapper.h" # endif /* UID_WRAPPER_DISABLE */ #else /* UID_WRAPPER */ # define uwrap_enabled() 0 #endif /* UID_WRAPPER */ #endif ctdb-2.5.1.dfsg/lib/replace/replace-testsuite.h0000644000175000017500000000036312245023514021223 0ustar mathieumathieu#ifndef __LIB_REPLACE_REPLACE_TESTSUITE_H__ #define __LIB_REPLACE_REPLACE_TESTSUITE_H__ #include struct torture_context; bool torture_local_replace(struct torture_context *ctx); #endif /* __LIB_REPLACE_REPLACE_TESTSUITE_H__ */ ctdb-2.5.1.dfsg/lib/replace/getaddrinfo.c0000644000175000017500000002463712245023514020054 0ustar mathieumathieu/* PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*------------------------------------------------------------------------- * * getaddrinfo.c * Support getaddrinfo() on platforms that don't have it. * * We also supply getnameinfo() here, assuming that the platform will have * it if and only if it has getaddrinfo(). If this proves false on some * platform, we'll need to split this file and provide a separate configure * test for getnameinfo(). * * Copyright (c) 2003-2007, PostgreSQL Global Development Group * * Copyright (C) 2007 Jeremy Allison. * Modified to return multiple IPv4 addresses for Samba. * *------------------------------------------------------------------------- */ #include "replace.h" #include "system/network.h" #ifndef SMB_MALLOC #define SMB_MALLOC(s) malloc(s) #endif #ifndef SMB_STRDUP #define SMB_STRDUP(s) strdup(s) #endif static int check_hostent_err(struct hostent *hp) { if (!hp) { switch (h_errno) { case HOST_NOT_FOUND: case NO_DATA: return EAI_NONAME; case TRY_AGAIN: return EAI_AGAIN; case NO_RECOVERY: default: return EAI_FAIL; } } if (!hp->h_name || hp->h_addrtype != AF_INET) { return EAI_FAIL; } return 0; } static char *canon_name_from_hostent(struct hostent *hp, int *perr) { char *ret = NULL; *perr = check_hostent_err(hp); if (*perr) { return NULL; } ret = SMB_STRDUP(hp->h_name); if (!ret) { *perr = EAI_MEMORY; } return ret; } static char *get_my_canon_name(int *perr) { char name[HOST_NAME_MAX+1]; if (gethostname(name, HOST_NAME_MAX) == -1) { *perr = EAI_FAIL; return NULL; } /* Ensure null termination. */ name[HOST_NAME_MAX] = '\0'; return canon_name_from_hostent(gethostbyname(name), perr); } static char *get_canon_name_from_addr(struct in_addr ip, int *perr) { return canon_name_from_hostent( gethostbyaddr(&ip, sizeof(ip), AF_INET), perr); } static struct addrinfo *alloc_entry(const struct addrinfo *hints, struct in_addr ip, unsigned short port) { struct sockaddr_in *psin = NULL; struct addrinfo *ai = SMB_MALLOC(sizeof(*ai)); if (!ai) { return NULL; } memset(ai, '\0', sizeof(*ai)); psin = SMB_MALLOC(sizeof(*psin)); if (!psin) { free(ai); return NULL; } memset(psin, '\0', sizeof(*psin)); psin->sin_family = AF_INET; psin->sin_port = htons(port); psin->sin_addr = ip; ai->ai_flags = 0; ai->ai_family = AF_INET; ai->ai_socktype = hints->ai_socktype; ai->ai_protocol = hints->ai_protocol; ai->ai_addrlen = sizeof(*psin); ai->ai_addr = (struct sockaddr *) psin; ai->ai_canonname = NULL; ai->ai_next = NULL; return ai; } /* * get address info for a single ipv4 address. * * Bugs: - servname can only be a number, not text. */ static int getaddr_info_single_addr(const char *service, uint32_t addr, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo *ai = NULL; struct in_addr ip; unsigned short port = 0; if (service) { port = (unsigned short)atoi(service); } ip.s_addr = htonl(addr); ai = alloc_entry(hints, ip, port); if (!ai) { return EAI_MEMORY; } /* If we're asked for the canonical name, * make sure it returns correctly. */ if (!(hints->ai_flags & AI_NUMERICSERV) && hints->ai_flags & AI_CANONNAME) { int err; if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) { ai->ai_canonname = get_my_canon_name(&err); } else { ai->ai_canonname = get_canon_name_from_addr(ip,&err); } if (ai->ai_canonname == NULL) { freeaddrinfo(ai); return err; } } *res = ai; return 0; } /* * get address info for multiple ipv4 addresses. * * Bugs: - servname can only be a number, not text. */ static int getaddr_info_name(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo *listp = NULL, *prevp = NULL; char **pptr = NULL; int err; struct hostent *hp = NULL; unsigned short port = 0; if (service) { port = (unsigned short)atoi(service); } hp = gethostbyname(node); err = check_hostent_err(hp); if (err) { return err; } for(pptr = hp->h_addr_list; *pptr; pptr++) { struct in_addr ip = *(struct in_addr *)*pptr; struct addrinfo *ai = alloc_entry(hints, ip, port); if (!ai) { freeaddrinfo(listp); return EAI_MEMORY; } if (!listp) { listp = ai; prevp = ai; ai->ai_canonname = SMB_STRDUP(hp->h_name); if (!ai->ai_canonname) { freeaddrinfo(listp); return EAI_MEMORY; } } else { prevp->ai_next = ai; prevp = ai; } } *res = listp; return 0; } /* * get address info for ipv4 sockets. * * Bugs: - servname can only be a number, not text. */ int rep_getaddrinfo(const char *node, const char *service, const struct addrinfo * hintp, struct addrinfo ** res) { struct addrinfo hints; /* Setup the hints struct. */ if (hintp == NULL) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; } else { memcpy(&hints, hintp, sizeof(hints)); } if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) { return EAI_FAMILY; } if (hints.ai_socktype == 0) { hints.ai_socktype = SOCK_STREAM; } if (!node && !service) { return EAI_NONAME; } if (node) { if (node[0] == '\0') { return getaddr_info_single_addr(service, INADDR_ANY, &hints, res); } else if (hints.ai_flags & AI_NUMERICHOST) { struct in_addr ip; if (!inet_aton(node, &ip)) { return EAI_FAIL; } return getaddr_info_single_addr(service, ntohl(ip.s_addr), &hints, res); } else { return getaddr_info_name(node, service, &hints, res); } } else if (hints.ai_flags & AI_PASSIVE) { return getaddr_info_single_addr(service, INADDR_ANY, &hints, res); } return getaddr_info_single_addr(service, INADDR_LOOPBACK, &hints, res); } void rep_freeaddrinfo(struct addrinfo *res) { struct addrinfo *next = NULL; for (;res; res = next) { next = res->ai_next; if (res->ai_canonname) { free(res->ai_canonname); } if (res->ai_addr) { free(res->ai_addr); } free(res); } } const char *rep_gai_strerror(int errcode) { #ifdef HAVE_HSTRERROR int hcode; switch (errcode) { case EAI_NONAME: hcode = HOST_NOT_FOUND; break; case EAI_AGAIN: hcode = TRY_AGAIN; break; case EAI_FAIL: default: hcode = NO_RECOVERY; break; } return hstrerror(hcode); #else /* !HAVE_HSTRERROR */ switch (errcode) { case EAI_NONAME: return "Unknown host"; case EAI_AGAIN: return "Host name lookup failure"; #ifdef EAI_BADFLAGS case EAI_BADFLAGS: return "Invalid argument"; #endif #ifdef EAI_FAMILY case EAI_FAMILY: return "Address family not supported"; #endif #ifdef EAI_MEMORY case EAI_MEMORY: return "Not enough memory"; #endif #ifdef EAI_NODATA case EAI_NODATA: return "No host data of that type was found"; #endif #ifdef EAI_SERVICE case EAI_SERVICE: return "Class type not found"; #endif #ifdef EAI_SOCKTYPE case EAI_SOCKTYPE: return "Socket type not supported"; #endif default: return "Unknown server error"; } #endif /* HAVE_HSTRERROR */ } static int gethostnameinfo(const struct sockaddr *sa, char *node, size_t nodelen, int flags) { int ret = -1; char *p = NULL; if (!(flags & NI_NUMERICHOST)) { struct hostent *hp = gethostbyaddr( &((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr), sa->sa_family); ret = check_hostent_err(hp); if (ret == 0) { /* Name looked up successfully. */ ret = snprintf(node, nodelen, "%s", hp->h_name); if (ret < 0 || (size_t)ret >= nodelen) { return EAI_MEMORY; } if (flags & NI_NOFQDN) { p = strchr(node,'.'); if (p) { *p = '\0'; } } return 0; } if (flags & NI_NAMEREQD) { /* If we require a name and didn't get one, * automatically fail. */ return ret; } /* Otherwise just fall into the numeric host code... */ } p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); ret = snprintf(node, nodelen, "%s", p); if (ret < 0 || (size_t)ret >= nodelen) { return EAI_MEMORY; } return 0; } static int getservicenameinfo(const struct sockaddr *sa, char *service, size_t servicelen, int flags) { int ret = -1; int port = ntohs(((struct sockaddr_in *)sa)->sin_port); if (!(flags & NI_NUMERICSERV)) { struct servent *se = getservbyport( port, (flags & NI_DGRAM) ? "udp" : "tcp"); if (se && se->s_name) { /* Service name looked up successfully. */ ret = snprintf(service, servicelen, "%s", se->s_name); if (ret < 0 || (size_t)ret >= servicelen) { return EAI_MEMORY; } return 0; } /* Otherwise just fall into the numeric service code... */ } ret = snprintf(service, servicelen, "%d", port); if (ret < 0 || (size_t)ret >= servicelen) { return EAI_MEMORY; } return 0; } /* * Convert an ipv4 address to a hostname. * * Bugs: - No IPv6 support. */ int rep_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *node, size_t nodelen, char *service, size_t servicelen, int flags) { /* Invalid arguments. */ if (sa == NULL || (node == NULL && service == NULL)) { return EAI_FAIL; } if (sa->sa_family != AF_INET) { return EAI_FAIL; } if (salen < sizeof(struct sockaddr_in)) { return EAI_FAIL; } if (node) { return gethostnameinfo(sa, node, nodelen, flags); } if (service) { return getservicenameinfo(sa, service, servicelen, flags); } return 0; } ctdb-2.5.1.dfsg/lib/replace/Makefile0000644000175000017500000000150312245023514017045 0ustar mathieumathieu# simple makefile wrapper to run waf WAF=WAF_MAKE=1 PATH=buildtools/bin:../../buildtools/bin:$$PATH waf all: $(WAF) build install: $(WAF) install uninstall: $(WAF) uninstall test: $(WAF) test $(TEST_OPTIONS) testenv: $(WAF) test --testenv $(TEST_OPTIONS) quicktest: $(WAF) test --quick $(TEST_OPTIONS) dist: touch .tmplock WAFLOCK=.tmplock $(WAF) dist distcheck: touch .tmplock WAFLOCK=.tmplock $(WAF) distcheck clean: $(WAF) clean distclean: $(WAF) distclean reconfigure: configure $(WAF) reconfigure show_waf_options: $(WAF) --help # some compatibility make targets everything: all testsuite: all check: test torture: all # this should do an install as well, once install is finished installcheck: test etags: $(WAF) etags ctags: $(WAF) ctags bin/%:: FORCE $(WAF) --targets=`basename $@` FORCE: ctdb-2.5.1.dfsg/lib/replace/getaddrinfo.h0000644000175000017500000000614112245023514020047 0ustar mathieumathieu/* PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*------------------------------------------------------------------------- * * getaddrinfo.h * Support getaddrinfo() on platforms that don't have it. * * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO, * whether or not the library routine getaddrinfo() can be found. This * policy is needed because on some platforms a manually installed libbind.a * may provide getaddrinfo(), yet the system headers may not provide the * struct definitions needed to call it. To avoid conflict with the libbind * definition in such cases, we rename our routines to pg_xxx() via macros. * in lib/replace we use rep_xxx() * This code will also work on platforms where struct addrinfo is defined * in the system headers but no getaddrinfo() can be located. * * Copyright (c) 2003-2007, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ #ifndef GETADDRINFO_H #define GETADDRINFO_H #ifndef HAVE_GETADDRINFO /* Rename private copies per comments above */ #ifdef getaddrinfo #undef getaddrinfo #endif #define getaddrinfo rep_getaddrinfo #define HAVE_GETADDRINFO #ifdef freeaddrinfo #undef freeaddrinfo #endif #define freeaddrinfo rep_freeaddrinfo #define HAVE_FREEADDRINFO #ifdef gai_strerror #undef gai_strerror #endif #define gai_strerror rep_gai_strerror #define HAVE_GAI_STRERROR #ifdef getnameinfo #undef getnameinfo #endif #define getnameinfo rep_getnameinfo #ifndef HAVE_GETNAMEINFO #define HAVE_GETNAMEINFO #endif extern int rep_getaddrinfo(const char *node, const char *service, const struct addrinfo * hints, struct addrinfo ** res); extern void rep_freeaddrinfo(struct addrinfo * res); extern const char *rep_gai_strerror(int errcode); extern int rep_getnameinfo(const struct sockaddr * sa, socklen_t salen, char *node, size_t nodelen, char *service, size_t servicelen, int flags); #endif /* HAVE_GETADDRINFO */ #endif /* GETADDRINFO_H */ ctdb-2.5.1.dfsg/lib/replace/libreplace_network.m40000644000175000017500000003755012245023514021535 0ustar mathieumathieuAC_DEFUN_ONCE(AC_LIBREPLACE_NETWORK_CHECKS, [ echo "LIBREPLACE_NETWORK_CHECKS: START" AC_DEFINE(LIBREPLACE_NETWORK_CHECKS, 1, [LIBREPLACE_NETWORK_CHECKS were used]) LIBREPLACE_NETWORK_OBJS="" LIBREPLACE_NETWORK_LIBS="" AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h arpa/inet.h) AC_CHECK_HEADERS(netinet/in_systm.h) AC_CHECK_HEADERS([netinet/ip.h], [], [],[ #include #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_NETINET_IN_SYSTM_H #include #endif ]) AC_CHECK_HEADERS(netinet/tcp.h netinet/in_ip.h) AC_CHECK_HEADERS(sys/sockio.h sys/un.h) AC_CHECK_HEADERS(sys/uio.h) dnl we need to check that net/if.h really can be used, to cope with hpux dnl where including it always fails AC_CACHE_CHECK([for usable net/if.h],libreplace_cv_USABLE_NET_IF_H,[ AC_COMPILE_IFELSE([AC_LANG_SOURCE([ AC_INCLUDES_DEFAULT #if HAVE_SYS_SOCKET_H # include #endif #include int main(void) {return 0;}])], [libreplace_cv_USABLE_NET_IF_H=yes], [libreplace_cv_USABLE_NET_IF_H=no] ) ]) if test x"$libreplace_cv_USABLE_NET_IF_H" = x"yes";then AC_DEFINE(HAVE_NET_IF_H, 1, usability of net/if.h) fi AC_HAVE_TYPE([socklen_t],[#include ]) AC_HAVE_TYPE([sa_family_t],[#include ]) AC_HAVE_TYPE([struct addrinfo], [#include ]) AC_HAVE_TYPE([struct sockaddr], [#include ]) AC_HAVE_TYPE([struct sockaddr_storage], [ #include #include #include ]) AC_HAVE_TYPE([struct sockaddr_in6], [ #include #include #include ]) if test x"$ac_cv_type_struct_sockaddr_storage" = x"yes"; then AC_CHECK_MEMBER(struct sockaddr_storage.ss_family, AC_DEFINE(HAVE_SS_FAMILY, 1, [Defined if struct sockaddr_storage has ss_family field]),, [ #include #include #include ]) if test x"$ac_cv_member_struct_sockaddr_storage_ss_family" != x"yes"; then AC_CHECK_MEMBER(struct sockaddr_storage.__ss_family, AC_DEFINE(HAVE___SS_FAMILY, 1, [Defined if struct sockaddr_storage has __ss_family field]),, [ #include #include #include ]) fi fi AC_CACHE_CHECK([for sin_len in sock],libreplace_cv_HAVE_SOCK_SIN_LEN,[ AC_TRY_COMPILE( [ #include #include #include ],[ struct sockaddr_in sock; sock.sin_len = sizeof(sock); ],[ libreplace_cv_HAVE_SOCK_SIN_LEN=yes ],[ libreplace_cv_HAVE_SOCK_SIN_LEN=no ]) ]) if test x"$libreplace_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then AC_DEFINE(HAVE_SOCK_SIN_LEN,1,[Whether the sockaddr_in struct has a sin_len property]) fi ############################################ # check for unix domain sockets AC_CACHE_CHECK([for unix domain sockets],libreplace_cv_HAVE_UNIXSOCKET,[ AC_TRY_COMPILE([ #include #include #include #include #include ],[ struct sockaddr_un sunaddr; sunaddr.sun_family = AF_UNIX; ],[ libreplace_cv_HAVE_UNIXSOCKET=yes ],[ libreplace_cv_HAVE_UNIXSOCKET=no ]) ]) if test x"$libreplace_cv_HAVE_UNIXSOCKET" = x"yes"; then AC_DEFINE(HAVE_UNIXSOCKET,1,[If we need to build with unixscoket support]) fi dnl The following test is roughly taken from the cvs sources. dnl dnl If we can't find connect, try looking in -lsocket, -lnsl, and -linet. dnl The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has dnl libsocket.so which has a bad implementation of gethostbyname (it dnl only looks in /etc/hosts), so we only look for -lsocket if we need dnl it. AC_CHECK_FUNCS(connect) if test x"$ac_cv_func_connect" = x"no"; then AC_CHECK_LIB_EXT(nsl_s, LIBREPLACE_NETWORK_LIBS, connect) AC_CHECK_LIB_EXT(nsl, LIBREPLACE_NETWORK_LIBS, connect) AC_CHECK_LIB_EXT(socket, LIBREPLACE_NETWORK_LIBS, connect) AC_CHECK_LIB_EXT(inet, LIBREPLACE_NETWORK_LIBS, connect) dnl We can't just call AC_CHECK_FUNCS(connect) here, dnl because the value has been cached. if test x"$ac_cv_lib_ext_nsl_s_connect" = x"yes" || test x"$ac_cv_lib_ext_nsl_connect" = x"yes" || test x"$ac_cv_lib_ext_socket_connect" = x"yes" || test x"$ac_cv_lib_ext_inet_connect" = x"yes" then AC_DEFINE(HAVE_CONNECT,1,[Whether the system has connect()]) fi fi AC_CHECK_FUNCS(gethostbyname) if test x"$ac_cv_func_gethostbyname" = x"no"; then AC_CHECK_LIB_EXT(nsl_s, LIBREPLACE_NETWORK_LIBS, gethostbyname) AC_CHECK_LIB_EXT(nsl, LIBREPLACE_NETWORK_LIBS, gethostbyname) AC_CHECK_LIB_EXT(socket, LIBREPLACE_NETWORK_LIBS, gethostbyname) dnl We can't just call AC_CHECK_FUNCS(gethostbyname) here, dnl because the value has been cached. if test x"$ac_cv_lib_ext_nsl_s_gethostbyname" = x"yes" || test x"$ac_cv_lib_ext_nsl_gethostbyname" = x"yes" || test x"$ac_cv_lib_ext_socket_gethostbyname" = x"yes" then AC_DEFINE(HAVE_GETHOSTBYNAME,1, [Whether the system has gethostbyname()]) fi fi dnl HP-UX has if_nametoindex in -lipv6 AC_CHECK_FUNCS(if_nametoindex) if test x"$ac_cv_func_if_nametoindex" = x"no"; then AC_CHECK_LIB_EXT(ipv6, LIBREPLACE_NETWORK_LIBS, if_nametoindex) dnl We can't just call AC_CHECK_FUNCS(if_nametoindex) here, dnl because the value has been cached. if test x"$ac_cv_lib_ext_ipv6_if_nametoindex" = x"yes" then AC_DEFINE(HAVE_IF_NAMETOINDEX, 1, [Whether the system has if_nametoindex()]) fi fi # The following tests need LIBS="${LIBREPLACE_NETWORK_LIBS}" old_LIBS=$LIBS LIBS="${LIBREPLACE_NETWORK_LIBS}" libreplace_SAVE_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -I$libreplacedir" AC_CHECK_FUNCS(socketpair,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} $libreplacedir/socketpair.o"]) AC_CACHE_CHECK([for broken inet_ntoa],libreplace_cv_REPLACE_INET_NTOA,[ AC_TRY_RUN([ #include #include #include #include #ifdef HAVE_ARPA_INET_H #include #endif main() { struct in_addr ip; ip.s_addr = 0x12345678; if (strcmp(inet_ntoa(ip),"18.52.86.120") && strcmp(inet_ntoa(ip),"120.86.52.18")) { exit(0); } exit(1);}], libreplace_cv_REPLACE_INET_NTOA=yes,libreplace_cv_REPLACE_INET_NTOA=no,libreplace_cv_REPLACE_INET_NTOA=cross)]) AC_CHECK_FUNCS(inet_ntoa,[],[libreplace_cv_REPLACE_INET_NTOA=yes]) if test x"$libreplace_cv_REPLACE_INET_NTOA" = x"yes"; then AC_DEFINE(REPLACE_INET_NTOA,1,[Whether inet_ntoa should be replaced]) LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} $libreplacedir/inet_ntoa.o" fi AC_CHECK_FUNCS(inet_aton,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} $libreplacedir/inet_aton.o"]) AC_CHECK_FUNCS(inet_ntop,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} $libreplacedir/inet_ntop.o"]) AC_CHECK_FUNCS(inet_pton,[],[LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} $libreplacedir/inet_pton.o"]) dnl test for getaddrinfo/getnameinfo AC_CACHE_CHECK([for getaddrinfo],libreplace_cv_HAVE_GETADDRINFO,[ AC_TRY_LINK([ #include #if STDC_HEADERS #include #include #endif #include #include ], [ struct sockaddr sa; struct addrinfo *ai = NULL; int ret = getaddrinfo(NULL, NULL, NULL, &ai); if (ret != 0) { const char *es = gai_strerror(ret); } freeaddrinfo(ai); ret = getnameinfo(&sa, sizeof(sa), NULL, 0, NULL, 0, 0); ], libreplace_cv_HAVE_GETADDRINFO=yes,libreplace_cv_HAVE_GETADDRINFO=no)]) if test x"$libreplace_cv_HAVE_GETADDRINFO" = x"yes"; then # getaddrinfo is broken on some AIX systems # see bug 5910, use our replacements if we detect # a broken system. AC_TRY_RUN([ #include #include #include #include int main(int argc, const char *argv[]) { struct addrinfo hints = {0,}; struct addrinfo *ppres; const char hostname1[] = "0.0.0.0"; const char hostname2[] = "127.0.0.1"; const char hostname3[] = "::"; hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_NUMERICHOST|AI_PASSIVE|AI_ADDRCONFIG; /* Test for broken flag combination on AIX. */ if (getaddrinfo(hostname1, NULL, &hints, &ppres) == EAI_BADFLAGS) { /* This fails on an IPv6-only box, but not with the EAI_BADFLAGS error. */ return 1; } if (getaddrinfo(hostname2, NULL, &hints, &ppres) == 0) { /* IPv4 lookup works - good enough. */ return 0; } /* Uh-oh, no IPv4. Are we IPv6-only ? */ return getaddrinfo(hostname3, NULL, &hints, &ppres) != 0 ? 1 : 0; }], libreplace_cv_HAVE_GETADDRINFO=yes, libreplace_cv_HAVE_GETADDRINFO=no) fi if test x"$libreplace_cv_HAVE_GETADDRINFO" = x"yes"; then AC_DEFINE(HAVE_GETADDRINFO,1,[Whether the system has getaddrinfo]) AC_DEFINE(HAVE_GETNAMEINFO,1,[Whether the system has getnameinfo]) AC_DEFINE(HAVE_FREEADDRINFO,1,[Whether the system has freeaddrinfo]) AC_DEFINE(HAVE_GAI_STRERROR,1,[Whether the system has gai_strerror]) else LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} $libreplacedir/getaddrinfo.o" fi AC_CHECK_HEADERS([ifaddrs.h]) dnl Used when getifaddrs is not available AC_CHECK_MEMBERS([struct sockaddr.sa_len], [AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1, [Whether struct sockaddr has a sa_len member])], [], [#include ]) dnl test for getifaddrs and freeifaddrs AC_CACHE_CHECK([for getifaddrs and freeifaddrs],libreplace_cv_HAVE_GETIFADDRS,[ AC_TRY_LINK([ #include #if STDC_HEADERS #include #include #endif #include #include #include #include #include ], [ struct ifaddrs *ifp = NULL; int ret = getifaddrs (&ifp); freeifaddrs(ifp); ], libreplace_cv_HAVE_GETIFADDRS=yes,libreplace_cv_HAVE_GETIFADDRS=no)]) if test x"$libreplace_cv_HAVE_GETIFADDRS" = x"yes"; then AC_DEFINE(HAVE_GETIFADDRS,1,[Whether the system has getifaddrs]) AC_DEFINE(HAVE_FREEIFADDRS,1,[Whether the system has freeifaddrs]) AC_DEFINE(HAVE_STRUCT_IFADDRS,1,[Whether struct ifaddrs is available]) fi ################## # look for a method of finding the list of network interfaces iface=no; AC_CACHE_CHECK([for iface getifaddrs],libreplace_cv_HAVE_IFACE_GETIFADDRS,[ AC_TRY_RUN([ #define HAVE_IFACE_GETIFADDRS 1 #define NO_CONFIG_H 1 #define AUTOCONF_TEST 1 #define SOCKET_WRAPPER_NOT_REPLACE #include "$libreplacedir/replace.c" #include "$libreplacedir/inet_ntop.c" #include "$libreplacedir/snprintf.c" #include "$libreplacedir/getifaddrs.c" #define getifaddrs_test main #include "$libreplacedir/test/getifaddrs.c"], libreplace_cv_HAVE_IFACE_GETIFADDRS=yes,libreplace_cv_HAVE_IFACE_GETIFADDRS=no,libreplace_cv_HAVE_IFACE_GETIFADDRS=cross)]) if test x"$libreplace_cv_HAVE_IFACE_GETIFADDRS" = x"yes"; then iface=yes;AC_DEFINE(HAVE_IFACE_GETIFADDRS,1,[Whether iface getifaddrs is available]) else LIBREPLACE_NETWORK_OBJS="${LIBREPLACE_NETWORK_OBJS} $libreplacedir/getifaddrs.o" fi if test $iface = no; then AC_CACHE_CHECK([for iface AIX],libreplace_cv_HAVE_IFACE_AIX,[ AC_TRY_RUN([ #define HAVE_IFACE_AIX 1 #define NO_CONFIG_H 1 #define AUTOCONF_TEST 1 #undef _XOPEN_SOURCE_EXTENDED #define SOCKET_WRAPPER_NOT_REPLACE #include "$libreplacedir/replace.c" #include "$libreplacedir/inet_ntop.c" #include "$libreplacedir/snprintf.c" #include "$libreplacedir/getifaddrs.c" #define getifaddrs_test main #include "$libreplacedir/test/getifaddrs.c"], libreplace_cv_HAVE_IFACE_AIX=yes,libreplace_cv_HAVE_IFACE_AIX=no,libreplace_cv_HAVE_IFACE_AIX=cross)]) if test x"$libreplace_cv_HAVE_IFACE_AIX" = x"yes"; then iface=yes;AC_DEFINE(HAVE_IFACE_AIX,1,[Whether iface AIX is available]) fi fi if test $iface = no; then AC_CACHE_CHECK([for iface ifconf],libreplace_cv_HAVE_IFACE_IFCONF,[ AC_TRY_RUN([ #define HAVE_IFACE_IFCONF 1 #define NO_CONFIG_H 1 #define AUTOCONF_TEST 1 #define SOCKET_WRAPPER_NOT_REPLACE #include "$libreplacedir/replace.c" #include "$libreplacedir/inet_ntop.c" #include "$libreplacedir/snprintf.c" #include "$libreplacedir/getifaddrs.c" #define getifaddrs_test main #include "$libreplacedir/test/getifaddrs.c"], libreplace_cv_HAVE_IFACE_IFCONF=yes,libreplace_cv_HAVE_IFACE_IFCONF=no,libreplace_cv_HAVE_IFACE_IFCONF=cross)]) if test x"$libreplace_cv_HAVE_IFACE_IFCONF" = x"yes"; then iface=yes;AC_DEFINE(HAVE_IFACE_IFCONF,1,[Whether iface ifconf is available]) fi fi if test $iface = no; then AC_CACHE_CHECK([for iface ifreq],libreplace_cv_HAVE_IFACE_IFREQ,[ AC_TRY_RUN([ #define HAVE_IFACE_IFREQ 1 #define NO_CONFIG_H 1 #define AUTOCONF_TEST 1 #define SOCKET_WRAPPER_NOT_REPLACE #include "$libreplacedir/replace.c" #include "$libreplacedir/inet_ntop.c" #include "$libreplacedir/snprintf.c" #include "$libreplacedir/getifaddrs.c" #define getifaddrs_test main #include "$libreplacedir/test/getifaddrs.c"], libreplace_cv_HAVE_IFACE_IFREQ=yes,libreplace_cv_HAVE_IFACE_IFREQ=no,libreplace_cv_HAVE_IFACE_IFREQ=cross)]) if test x"$libreplace_cv_HAVE_IFACE_IFREQ" = x"yes"; then iface=yes;AC_DEFINE(HAVE_IFACE_IFREQ,1,[Whether iface ifreq is available]) fi fi dnl Some old Linux systems have broken header files and dnl miss the IPV6_V6ONLY define in netinet/in.h, dnl but have it in linux/in6.h. dnl We can't include both files so we just check if the value dnl if defined and do the replacement in system/network.h AC_CACHE_CHECK([for IPV6_V6ONLY support],libreplace_cv_HAVE_IPV6_V6ONLY,[ AC_TRY_COMPILE([ #include /* for NULL */ #include #include #include #include ], [ #ifndef IPV6_V6ONLY #error no IPV6_V6ONLY #endif ],[ libreplace_cv_HAVE_IPV6_V6ONLY=yes ],[ libreplace_cv_HAVE_IPV6_V6ONLY=no ]) ]) if test x"$libreplace_cv_HAVE_IPV6_V6ONLY" != x"yes"; then dnl test for IPV6_V6ONLY AC_CACHE_CHECK([for IPV6_V6ONLY in linux/in6.h],libreplace_cv_HAVE_LINUX_IPV6_V6ONLY_26,[ AC_TRY_COMPILE([ #include ], [ #if (IPV6_V6ONLY != 26) #error no linux IPV6_V6ONLY #endif ],[ libreplace_cv_HAVE_LINUX_IPV6_V6ONLY_26=yes ],[ libreplace_cv_HAVE_LINUX_IPV6_V6ONLY_26=no ]) ]) if test x"$libreplace_cv_HAVE_LINUX_IPV6_V6ONLY_26" = x"yes"; then AC_DEFINE(HAVE_LINUX_IPV6_V6ONLY_26,1,[Whether the system has IPV6_V6ONLY in linux/in6.h]) fi fi dnl test for ipv6 AC_CACHE_CHECK([for ipv6 support],libreplace_cv_HAVE_IPV6,[ AC_TRY_LINK([ #include /* for NULL */ #include #include #include #include ], [ struct sockaddr_storage sa_store; struct addrinfo *ai = NULL; struct in6_addr in6addr; int idx = if_nametoindex("iface1"); int s = socket(AF_INET6, SOCK_STREAM, 0); int ret = getaddrinfo(NULL, NULL, NULL, &ai); if (ret != 0) { const char *es = gai_strerror(ret); } freeaddrinfo(ai); { int val = 1; #ifdef HAVE_LINUX_IPV6_V6ONLY_26 #define IPV6_V6ONLY 26 #endif ret = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&val, sizeof(val)); } ],[ libreplace_cv_HAVE_IPV6=yes ],[ libreplace_cv_HAVE_IPV6=no ]) ]) if test x"$libreplace_cv_HAVE_IPV6" = x"yes"; then AC_DEFINE(HAVE_IPV6,1,[Whether the system has IPv6 support]) fi LIBS=$old_LIBS CPPFLAGS="$libreplace_SAVE_CPPFLAGS" AC_CACHE_CHECK([for SO_PEERCRED],libreplace_cv_HAVE_PEERCRED,[ AC_TRY_COMPILE([#include #include ], [struct ucred cred; socklen_t cred_len; int ret = getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len); ], libreplace_cv_HAVE_PEERCRED=yes,libreplace_cv_HAVE_PEERCRED=no,libreplace_cv_HAVE_PEERCRED=cross)]) if test x"$libreplace_cv_HAVE_PEERCRED" = x"yes"; then AC_DEFINE(HAVE_PEERCRED,1,[Whether we can use SO_PEERCRED to get socket credentials]) fi AC_CACHE_CHECK([for getpeereid],libreplace_cv_HAVE_GETPEEREID,[ AC_TRY_LINK([#include #include ], [uid_t uid; gid_t gid; int ret; ret = getpeereid(0, &uid, &gid); ], libreplace_cv_HAVE_GETPEEREID=yes,libreplace_cv_HAVE_GETPEEREID=no)]) if test x"$libreplace_cv_HAVE_GETPEEREID" = xyes; then AC_DEFINE(HAVE_GETPEEREID,1, [Whether we have getpeereid to get socket credentials]) fi LIBREPLACEOBJ="${LIBREPLACEOBJ} ${LIBREPLACE_NETWORK_OBJS}" echo "LIBREPLACE_NETWORK_CHECKS: END" ]) dnl end AC_LIBREPLACE_NETWORK_CHECKS ctdb-2.5.1.dfsg/lib/replace/.checker_innocent0000644000175000017500000000024612245023514020712 0ustar mathieumathieu>>>MISTAKE21_create_files_6a9e68ada99a97cb >>>MISTAKE21_os2_delete_9b2bfa7f38711d09 >>>MISTAKE21_os2_delete_2fcc29aaa99a97cb >>>SECURITY2_os2_delete_9b2bfa7f1c9396ca ctdb-2.5.1.dfsg/lib/replace/strptime.c0000644000175000017500000005675512245023514017443 0ustar mathieumathieu/* Convert a string representation of time to a time value. Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1996. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; see the file COPYING.LIB. If not, see . */ /* XXX This version of the implementation is not really complete. Some of the fields cannot add information alone. But if seeing some of them in the same format (such as year, week and weekday) this is enough information for determining the date. */ #include "replace.h" #include "system/locale.h" #include "system/time.h" #ifndef __P # if defined (__GNUC__) || (defined (__STDC__) && __STDC__) # define __P(args) args # else # define __P(args) () # endif /* GCC. */ #endif /* Not __P. */ #if ! HAVE_LOCALTIME_R && ! defined localtime_r # ifdef _LIBC # define localtime_r __localtime_r # else /* Approximate localtime_r as best we can in its absence. */ # define localtime_r my_localtime_r static struct tm *localtime_r __P ((const time_t *, struct tm *)); static struct tm * localtime_r (t, tp) const time_t *t; struct tm *tp; { struct tm *l = localtime (t); if (! l) return 0; *tp = *l; return tp; } # endif /* ! _LIBC */ #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */ #define match_char(ch1, ch2) if (ch1 != ch2) return NULL #if defined __GNUC__ && __GNUC__ >= 2 # define match_string(cs1, s2) \ ({ size_t len = strlen (cs1); \ int result = strncasecmp ((cs1), (s2), len) == 0; \ if (result) (s2) += len; \ result; }) #else /* Oh come on. Get a reasonable compiler. */ # define match_string(cs1, s2) \ (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1)) #endif /* We intentionally do not use isdigit() for testing because this will lead to problems with the wide character version. */ #define get_number(from, to, n) \ do { \ int __n = n; \ val = 0; \ while (*rp == ' ') \ ++rp; \ if (*rp < '0' || *rp > '9') \ return NULL; \ do { \ val *= 10; \ val += *rp++ - '0'; \ } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \ if (val < from || val > to) \ return NULL; \ } while (0) #ifdef _NL_CURRENT # define get_alt_number(from, to, n) \ ({ \ __label__ do_normal; \ if (*decided != raw) \ { \ const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \ int __n = n; \ int any = 0; \ while (*rp == ' ') \ ++rp; \ val = 0; \ do { \ val *= 10; \ while (*alts != '\0') \ { \ size_t len = strlen (alts); \ if (strncasecmp (alts, rp, len) == 0) \ break; \ alts += len + 1; \ ++val; \ } \ if (*alts == '\0') \ { \ if (*decided == not && ! any) \ goto do_normal; \ /* If we haven't read anything it's an error. */ \ if (! any) \ return NULL; \ /* Correct the premature multiplication. */ \ val /= 10; \ break; \ } \ else \ *decided = loc; \ } while (--__n > 0 && val * 10 <= to); \ if (val < from || val > to) \ return NULL; \ } \ else \ { \ do_normal: \ get_number (from, to, n); \ } \ 0; \ }) #else # define get_alt_number(from, to, n) \ /* We don't have the alternate representation. */ \ get_number(from, to, n) #endif #define recursive(new_fmt) \ (*(new_fmt) != '\0' \ && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL) #ifdef _LIBC /* This is defined in locale/C-time.c in the GNU libc. */ extern const struct locale_data _nl_C_LC_TIME; extern const unsigned short int __mon_yday[2][13]; # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string) # define ab_weekday_name \ (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string) # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string) # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string) # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string) # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string) # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string) # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string) # define HERE_T_FMT_AMPM \ (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string) # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string) # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n) #else static char const weekday_name[][10] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static char const ab_weekday_name[][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char const month_name[][10] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static char const ab_month_name[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y" # define HERE_D_FMT "%m/%d/%y" # define HERE_AM_STR "AM" # define HERE_PM_STR "PM" # define HERE_T_FMT_AMPM "%I:%M:%S %p" # define HERE_T_FMT "%H:%M:%S" static const unsigned short int __mon_yday[2][13] = { /* Normal years. */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* Leap years. */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; #endif /* Status of lookup: do we use the locale data or the raw data? */ enum locale_status { not, loc, raw }; #ifndef __isleap /* Nonzero if YEAR is a leap year (every 4 years, except every 100th isn't, and every 400th is). */ # define __isleap(year) \ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) #endif /* Compute the day of the week. */ static void day_of_the_week (struct tm *tm) { /* We know that January 1st 1970 was a Thursday (= 4). Compute the the difference between this data in the one on TM and so determine the weekday. */ int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2); int wday = (-473 + (365 * (tm->tm_year - 70)) + (corr_year / 4) - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0) + (((corr_year / 4) / 25) / 4) + __mon_yday[0][tm->tm_mon] + tm->tm_mday - 1); tm->tm_wday = ((wday % 7) + 7) % 7; } /* Compute the day of the year. */ static void day_of_the_year (struct tm *tm) { tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon] + (tm->tm_mday - 1)); } static char * #ifdef _LIBC internal_function #endif strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm, enum locale_status *decided, int era_cnt)); static char * #ifdef _LIBC internal_function #endif strptime_internal (rp, fmt, tm, decided, era_cnt) const char *rp; const char *fmt; struct tm *tm; enum locale_status *decided; int era_cnt; { int cnt; size_t val; int have_I, is_pm; int century, want_century; int want_era; int have_wday, want_xday; int have_yday; int have_mon, have_mday; #ifdef _NL_CURRENT const char *rp_backup; size_t num_eras; struct era_entry *era; era = NULL; #endif have_I = is_pm = 0; century = -1; want_century = 0; want_era = 0; have_wday = want_xday = have_yday = have_mon = have_mday = 0; while (*fmt != '\0') { /* A white space in the format string matches 0 more or white space in the input string. */ if (isspace (*fmt)) { while (isspace (*rp)) ++rp; ++fmt; continue; } /* Any character but `%' must be matched by the same character in the iput string. */ if (*fmt != '%') { match_char (*fmt++, *rp++); continue; } ++fmt; #ifndef _NL_CURRENT /* We need this for handling the `E' modifier. */ start_over: #endif #ifdef _NL_CURRENT /* Make back up of current processing pointer. */ rp_backup = rp; #endif switch (*fmt++) { case '%': /* Match the `%' character itself. */ match_char ('%', *rp++); break; case 'a': case 'A': /* Match day of week. */ for (cnt = 0; cnt < 7; ++cnt) { #ifdef _NL_CURRENT if (*decided !=raw) { if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp)) { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt), weekday_name[cnt])) *decided = loc; break; } if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp)) { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), ab_weekday_name[cnt])) *decided = loc; break; } } #endif if (*decided != loc && (match_string (weekday_name[cnt], rp) || match_string (ab_weekday_name[cnt], rp))) { *decided = raw; break; } } if (cnt == 7) /* Does not match a weekday name. */ return NULL; tm->tm_wday = cnt; have_wday = 1; break; case 'b': case 'B': case 'h': /* Match month name. */ for (cnt = 0; cnt < 12; ++cnt) { #ifdef _NL_CURRENT if (*decided !=raw) { if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp)) { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt), month_name[cnt])) *decided = loc; break; } if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp)) { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), ab_month_name[cnt])) *decided = loc; break; } } #endif if (match_string (month_name[cnt], rp) || match_string (ab_month_name[cnt], rp)) { *decided = raw; break; } } if (cnt == 12) /* Does not match a month name. */ return NULL; tm->tm_mon = cnt; want_xday = 1; break; case 'c': /* Match locale's date and time format. */ #ifdef _NL_CURRENT if (*decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT))) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT)) *decided = loc; want_xday = 1; break; } *decided = raw; } #endif if (!recursive (HERE_D_T_FMT)) return NULL; want_xday = 1; break; case 'C': /* Match century number. */ #ifdef _NL_CURRENT match_century: #endif get_number (0, 99, 2); century = val; want_xday = 1; break; case 'd': case 'e': /* Match day of month. */ get_number (1, 31, 2); tm->tm_mday = val; have_mday = 1; want_xday = 1; break; case 'F': if (!recursive ("%Y-%m-%d")) return NULL; want_xday = 1; break; case 'x': #ifdef _NL_CURRENT if (*decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, D_FMT))) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT)) *decided = loc; want_xday = 1; break; } *decided = raw; } #endif /* Fall through. */ case 'D': /* Match standard day format. */ if (!recursive (HERE_D_FMT)) return NULL; want_xday = 1; break; case 'k': case 'H': /* Match hour in 24-hour clock. */ get_number (0, 23, 2); tm->tm_hour = val; have_I = 0; break; case 'I': /* Match hour in 12-hour clock. */ get_number (1, 12, 2); tm->tm_hour = val % 12; have_I = 1; break; case 'j': /* Match day number of year. */ get_number (1, 366, 3); tm->tm_yday = val - 1; have_yday = 1; break; case 'm': /* Match number of month. */ get_number (1, 12, 2); tm->tm_mon = val - 1; have_mon = 1; want_xday = 1; break; case 'M': /* Match minute. */ get_number (0, 59, 2); tm->tm_min = val; break; case 'n': case 't': /* Match any white space. */ while (isspace (*rp)) ++rp; break; case 'p': /* Match locale's equivalent of AM/PM. */ #ifdef _NL_CURRENT if (*decided != raw) { if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp)) { if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR)) *decided = loc; break; } if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp)) { if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR)) *decided = loc; is_pm = 1; break; } *decided = raw; } #endif if (!match_string (HERE_AM_STR, rp)) { if (match_string (HERE_PM_STR, rp)) { is_pm = 1; } else { return NULL; } } break; case 'r': #ifdef _NL_CURRENT if (*decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM))) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM), HERE_T_FMT_AMPM)) *decided = loc; break; } *decided = raw; } #endif if (!recursive (HERE_T_FMT_AMPM)) return NULL; break; case 'R': if (!recursive ("%H:%M")) return NULL; break; case 's': { /* The number of seconds may be very high so we cannot use the `get_number' macro. Instead read the number character for character and construct the result while doing this. */ time_t secs = 0; if (*rp < '0' || *rp > '9') /* We need at least one digit. */ return NULL; do { secs *= 10; secs += *rp++ - '0'; } while (*rp >= '0' && *rp <= '9'); if (localtime_r (&secs, tm) == NULL) /* Error in function. */ return NULL; } break; case 'S': get_number (0, 61, 2); tm->tm_sec = val; break; case 'X': #ifdef _NL_CURRENT if (*decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, T_FMT))) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT)) *decided = loc; break; } *decided = raw; } #endif /* Fall through. */ case 'T': if (!recursive (HERE_T_FMT)) return NULL; break; case 'u': get_number (1, 7, 1); tm->tm_wday = val % 7; have_wday = 1; break; case 'g': get_number (0, 99, 2); /* XXX This cannot determine any field in TM. */ break; case 'G': if (*rp < '0' || *rp > '9') return NULL; /* XXX Ignore the number since we would need some more information to compute a real date. */ do ++rp; while (*rp >= '0' && *rp <= '9'); break; case 'U': case 'V': case 'W': get_number (0, 53, 2); /* XXX This cannot determine any field in TM without some information. */ break; case 'w': /* Match number of weekday. */ get_number (0, 6, 1); tm->tm_wday = val; have_wday = 1; break; case 'y': #ifdef _NL_CURRENT match_year_in_century: #endif /* Match year within century. */ get_number (0, 99, 2); /* The "Year 2000: The Millennium Rollover" paper suggests that values in the range 69-99 refer to the twentieth century. */ tm->tm_year = val >= 69 ? val : val + 100; /* Indicate that we want to use the century, if specified. */ want_century = 1; want_xday = 1; break; case 'Y': /* Match year including century number. */ get_number (0, 9999, 4); tm->tm_year = val - 1900; want_century = 0; want_xday = 1; break; case 'Z': /* XXX How to handle this? */ break; case 'E': #ifdef _NL_CURRENT switch (*fmt++) { case 'c': /* Match locale's alternate date and time format. */ if (*decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, D_T_FMT); if (!recursive (fmt)) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_D_T_FMT)) *decided = loc; want_xday = 1; break; } *decided = raw; } /* The C locale has no era information, so use the normal representation. */ if (!recursive (HERE_D_T_FMT)) return NULL; want_xday = 1; break; case 'C': if (*decided != raw) { if (era_cnt >= 0) { era = _nl_select_era_entry (era_cnt); if (match_string (era->era_name, rp)) { *decided = loc; break; } else return NULL; } else { num_eras = _NL_CURRENT_WORD (LC_TIME, _NL_TIME_ERA_NUM_ENTRIES); for (era_cnt = 0; era_cnt < (int) num_eras; ++era_cnt, rp = rp_backup) { era = _nl_select_era_entry (era_cnt); if (match_string (era->era_name, rp)) { *decided = loc; break; } } if (era_cnt == (int) num_eras) { era_cnt = -1; if (*decided == loc) return NULL; } else break; } *decided = raw; } /* The C locale has no era information, so use the normal representation. */ goto match_century; case 'y': if (*decided == raw) goto match_year_in_century; get_number(0, 9999, 4); tm->tm_year = val; want_era = 1; want_xday = 1; break; case 'Y': if (*decided != raw) { num_eras = _NL_CURRENT_WORD (LC_TIME, _NL_TIME_ERA_NUM_ENTRIES); for (era_cnt = 0; era_cnt < (int) num_eras; ++era_cnt, rp = rp_backup) { era = _nl_select_era_entry (era_cnt); if (recursive (era->era_format)) break; } if (era_cnt == (int) num_eras) { era_cnt = -1; if (*decided == loc) return NULL; else rp = rp_backup; } else { *decided = loc; era_cnt = -1; break; } *decided = raw; } get_number (0, 9999, 4); tm->tm_year = val - 1900; want_century = 0; want_xday = 1; break; case 'x': if (*decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, D_FMT); if (!recursive (fmt)) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_D_FMT)) *decided = loc; break; } *decided = raw; } if (!recursive (HERE_D_FMT)) return NULL; break; case 'X': if (*decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, T_FMT); if (!recursive (fmt)) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_T_FMT)) *decided = loc; break; } *decided = raw; } if (!recursive (HERE_T_FMT)) return NULL; break; default: return NULL; } break; #else /* We have no information about the era format. Just use the normal format. */ if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y' && *fmt != 'x' && *fmt != 'X') /* This is an illegal format. */ return NULL; goto start_over; #endif case 'O': switch (*fmt++) { case 'd': case 'e': /* Match day of month using alternate numeric symbols. */ get_alt_number (1, 31, 2); tm->tm_mday = val; have_mday = 1; want_xday = 1; break; case 'H': /* Match hour in 24-hour clock using alternate numeric symbols. */ get_alt_number (0, 23, 2); tm->tm_hour = val; have_I = 0; break; case 'I': /* Match hour in 12-hour clock using alternate numeric symbols. */ get_alt_number (1, 12, 2); tm->tm_hour = val - 1; have_I = 1; break; case 'm': /* Match month using alternate numeric symbols. */ get_alt_number (1, 12, 2); tm->tm_mon = val - 1; have_mon = 1; want_xday = 1; break; case 'M': /* Match minutes using alternate numeric symbols. */ get_alt_number (0, 59, 2); tm->tm_min = val; break; case 'S': /* Match seconds using alternate numeric symbols. */ get_alt_number (0, 61, 2); tm->tm_sec = val; break; case 'U': case 'V': case 'W': get_alt_number (0, 53, 2); /* XXX This cannot determine any field in TM without further information. */ break; case 'w': /* Match number of weekday using alternate numeric symbols. */ get_alt_number (0, 6, 1); tm->tm_wday = val; have_wday = 1; break; case 'y': /* Match year within century using alternate numeric symbols. */ get_alt_number (0, 99, 2); tm->tm_year = val >= 69 ? val : val + 100; want_xday = 1; break; default: return NULL; } break; default: return NULL; } } if (have_I && is_pm) tm->tm_hour += 12; if (century != -1) { if (want_century) tm->tm_year = tm->tm_year % 100 + (century - 19) * 100; else /* Only the century, but not the year. Strange, but so be it. */ tm->tm_year = (century - 19) * 100; } #ifdef _NL_CURRENT if (era_cnt != -1) { era = _nl_select_era_entry(era_cnt); if (want_era) tm->tm_year = (era->start_date[0] + ((tm->tm_year - era->offset) * era->absolute_direction)); else /* Era start year assumed. */ tm->tm_year = era->start_date[0]; } else #endif if (want_era) return NULL; if (want_xday && !have_wday) { if ( !(have_mon && have_mday) && have_yday) { /* We don't have tm_mon and/or tm_mday, compute them. */ int t_mon = 0; while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) t_mon++; if (!have_mon) tm->tm_mon = t_mon - 1; if (!have_mday) tm->tm_mday = (tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); } day_of_the_week (tm); } if (want_xday && !have_yday) day_of_the_year (tm); return discard_const_p(char, rp); } char *rep_strptime(const char *buf, const char *format, struct tm *tm) { enum locale_status decided; #ifdef _NL_CURRENT decided = not; #else decided = raw; #endif return strptime_internal (buf, format, tm, &decided, -1); } ctdb-2.5.1.dfsg/lib/replace/repdir_getdirentries.c0000644000175000017500000001062312245023514021771 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Copyright (C) Andrew Tridgell 2005 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ /* a replacement for opendir/readdir/telldir/seekdir/closedir for BSD systems using getdirentries This is needed because the existing directory handling in FreeBSD and OpenBSD (and possibly NetBSD) doesn't correctly handle unlink() on files in a directory where telldir() has been used. On a block boundary it will occasionally miss a file when seekdir() is used to return to a position previously recorded with telldir(). This also fixes a severe performance and memory usage problem with telldir() on BSD systems. Each call to telldir() in BSD adds an entry to a linked list, and those entries are cleaned up on closedir(). This means with a large directory closedir() can take an arbitrary amount of time, causing network timeouts as millions of telldir() entries are freed Note! This replacement code is not portable. It relies on getdirentries() always leaving the file descriptor at a seek offset that is a multiple of DIR_BUF_SIZE. If the code detects that this doesn't happen then it will abort(). It also does not handle directories with offsets larger than can be stored in a long, This code is available under other free software licenses as well. Contact the author. */ #include "replace.h" #include #include #include #include #include #include #include #define DIR_BUF_BITS 9 #define DIR_BUF_SIZE (1<fd = open(dname, O_RDONLY); if (d->fd == -1) { free(d); return NULL; } if (fstat(d->fd, &sb) < 0) { close(d->fd); free(d); return NULL; } if (!S_ISDIR(sb.st_mode)) { close(d->fd); free(d); errno = ENOTDIR; return NULL; } d->ofs = 0; d->seekpos = 0; d->nbytes = 0; return (DIR *)d; } struct dirent *readdir(DIR *dir) { struct dir_buf *d = (struct dir_buf *)dir; struct dirent *de; if (d->ofs >= d->nbytes) { long pos; d->nbytes = getdirentries(d->fd, d->buf, DIR_BUF_SIZE, &pos); d->seekpos = pos; d->ofs = 0; } if (d->ofs >= d->nbytes) { return NULL; } de = (struct dirent *)&d->buf[d->ofs]; d->ofs += de->d_reclen; return de; } #ifdef TELLDIR_TAKES_CONST_DIR long telldir(const DIR *dir) #else long telldir(DIR *dir) #endif { struct dir_buf *d = (struct dir_buf *)dir; if (d->ofs >= d->nbytes) { d->seekpos = lseek(d->fd, 0, SEEK_CUR); d->ofs = 0; d->nbytes = 0; } /* this relies on seekpos always being a multiple of DIR_BUF_SIZE. Is that always true on BSD systems? */ if (d->seekpos & (DIR_BUF_SIZE-1)) { abort(); } return d->seekpos + d->ofs; } #ifdef SEEKDIR_RETURNS_INT int seekdir(DIR *dir, long ofs) #else void seekdir(DIR *dir, long ofs) #endif { struct dir_buf *d = (struct dir_buf *)dir; long pos; d->seekpos = lseek(d->fd, ofs & ~(DIR_BUF_SIZE-1), SEEK_SET); d->nbytes = getdirentries(d->fd, d->buf, DIR_BUF_SIZE, &pos); d->ofs = 0; while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) { if (readdir(dir) == NULL) break; } #ifdef SEEKDIR_RETURNS_INT return -1; #endif } void rewinddir(DIR *dir) { seekdir(dir, 0); } int closedir(DIR *dir) { struct dir_buf *d = (struct dir_buf *)dir; int r = close(d->fd); if (r != 0) { return r; } free(d); return 0; } #ifndef dirfd /* darn, this is a macro on some systems. */ int dirfd(DIR *dir) { struct dir_buf *d = (struct dir_buf *)dir; return d->fd; } #endif ctdb-2.5.1.dfsg/lib/replace/inet_ntop.c0000644000175000017500000001163212245023514017554 0ustar mathieumathieu/* * Copyright (C) 1996-2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "replace.h" #include "system/network.h" #define NS_INT16SZ 2 #define NS_IN6ADDRSZ 16 /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static const char *inet_ntop4(const unsigned char *src, char *dst, socklen_t size); #ifdef AF_INET6 static const char *inet_ntop6(const unsigned char *src, char *dst, socklen_t size); #endif /* char * * isc_net_ntop(af, src, dst, size) * convert a network format address to presentation format. * return: * pointer to presentation format address (`dst'), or NULL (see errno). * author: * Paul Vixie, 1996. */ const char * rep_inet_ntop(int af, const void *src, char *dst, socklen_t size) { switch (af) { case AF_INET: return (inet_ntop4(src, dst, size)); #ifdef AF_INET6 case AF_INET6: return (inet_ntop6(src, dst, size)); #endif default: errno = EAFNOSUPPORT; return (NULL); } /* NOTREACHED */ } /* const char * * inet_ntop4(src, dst, size) * format an IPv4 address * return: * `dst' (as a const) * notes: * (1) uses no statics * (2) takes a unsigned char* not an in_addr as input * author: * Paul Vixie, 1996. */ static const char * inet_ntop4(const unsigned char *src, char *dst, socklen_t size) { static const char *fmt = "%u.%u.%u.%u"; char tmp[sizeof "255.255.255.255"]; size_t len; len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]); if (len >= size) { errno = ENOSPC; return (NULL); } memcpy(dst, tmp, len + 1); return (dst); } /* const char * * isc_inet_ntop6(src, dst, size) * convert IPv6 binary address into presentation (printable) format * author: * Paul Vixie, 1996. */ #ifdef AF_INET6 static const char * inet_ntop6(const unsigned char *src, char *dst, socklen_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like * Crays, there is no such thing as an integer variable with 16 bits. * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; struct { int base, len; } best, cur; unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; int i, inc; /* * Preprocess: * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof words); for (i = 0; i < NS_IN6ADDRSZ; i++) words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = -1; best.len = 0; cur.base = -1; cur.len = 0; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { if (words[i] == 0) { if (cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } } if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; } if (best.base != -1 && best.len < 2) best.base = -1; /* * Format the result. */ tp = tmp; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { /* Are we inside the best run of 0x00's? */ if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { if (i == best.base) *tp++ = ':'; continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) *tp++ = ':'; /* Is this address an encapsulated IPv4? */ if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) return (NULL); tp += strlen(tp); break; } inc = snprintf(tp, 5, "%x", words[i]); if (inc >= 5) { abort(); } tp += inc; } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) *tp++ = ':'; *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((size_t)(tp - tmp) > size) { errno = ENOSPC; return (NULL); } memcpy(dst, tmp, tp - tmp); return (dst); } #endif /* AF_INET6 */ ctdb-2.5.1.dfsg/lib/replace/autoconf-2.60.m40000644000175000017500000001452612245023514020061 0ustar mathieumathieu# AC_GNU_SOURCE # -------------- AC_DEFUN([AC_GNU_SOURCE], [AH_VERBATIM([_GNU_SOURCE], [/* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif])dnl AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl AC_BEFORE([$0], [AC_RUN_IFELSE])dnl AC_DEFINE([_GNU_SOURCE]) ]) # _AC_C_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST, # ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE) # -------------------------------------------------------------- # Check whether the C compiler accepts features of STANDARD (e.g `c89', `c99') # by trying to compile a program of TEST-PROLOGUE and TEST-BODY. If this fails, # try again with each compiler option in the space-separated OPTION-LIST; if one # helps, append it to CC. If eventually successful, run ACTION-IF-AVAILABLE, # else ACTION-IF-UNAVAILABLE. AC_DEFUN([_AC_C_STD_TRY], [AC_MSG_CHECKING([for $CC option to accept ISO ]m4_translit($1, [c], [C])) AC_CACHE_VAL(ac_cv_prog_cc_$1, [ac_cv_prog_cc_$1=no ac_save_CC=$CC AC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])]) for ac_arg in '' $4 do CC="$ac_save_CC $ac_arg" _AC_COMPILE_IFELSE([], [ac_cv_prog_cc_$1=$ac_arg]) test "x$ac_cv_prog_cc_$1" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ])# AC_CACHE_VAL case "x$ac_cv_prog_cc_$1" in x) AC_MSG_RESULT([none needed]) ;; xno) AC_MSG_RESULT([unsupported]) ;; *) CC="$CC $ac_cv_prog_cc_$1" AC_MSG_RESULT([$ac_cv_prog_cc_$1]) ;; esac AS_IF([test "x$ac_cv_prog_cc_$1" != xno], [$5], [$6]) ])# _AC_C_STD_TRY # _AC_PROG_CC_C99 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE]) # ---------------------------------------------------------------- # If the C compiler is not in ISO C99 mode by default, try to add an # option to output variable CC to make it so. This macro tries # various options that select ISO C99 on some system or another. It # considers the compiler to be in ISO C99 mode if it handles mixed # code and declarations, _Bool, inline and restrict. AC_DEFUN([_AC_PROG_CC_C99], [_AC_C_STD_TRY([c99], [[#include #include #include #include #include struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict(ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy work. static void test_varargs(const char *format, ...) { va_list args; va_start(args, format); va_list args_copy; va_copy(args_copy, args); const char *str; int number; float fnumber; while (*format) { switch (*format++) { case 's': // string str = va_arg(args_copy, const char *); break; case 'd': // int number = va_arg(args_copy, int); break; case 'f': // float fnumber = (float) va_arg(args_copy, double); break; default: break; } } va_end(args_copy); va_end(args); } ]], [[ // Check bool and long long datatypes. _Bool success = false; long long int bignum = -1234567890LL; unsigned long long int ubignum = 1234567890uLL; // Check restrict. if (test_restrict("String literal") != 0) success = true; char *restrict newvar = "Another string"; // Check varargs. test_varargs("s, d' f .", "string", 65, 34.234); // Check incomplete arrays work. struct incomplete_array *ia = malloc(sizeof(struct incomplete_array) + (sizeof(double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = (double) i * 1.234; // Check named initialisers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[43] = 543; // work around unused variable warnings return bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'; ]], dnl Try dnl GCC -std=gnu99 (unused restrictive modes: -std=c99 -std=iso9899:1999) dnl AIX -qlanglvl=extc99 (unused restrictive mode: -qlanglvl=stdc99) dnl Intel ICC -c99 dnl IRIX -c99 dnl Solaris (unused because it causes the compiler to assume C99 semantics for dnl library functions, and this is invalid before Solaris 10: -xc99) dnl Tru64 -c99 dnl with extended modes being tried first. [[-std=gnu99 -c99 -qlanglvl=extc99]], [$1], [$2])[]dnl ])# _AC_PROG_CC_C99 # AC_PROG_CC_C99 # -------------- AC_DEFUN([AC_PROG_CC_C99], [ AC_REQUIRE([AC_PROG_CC])dnl _AC_PROG_CC_C99 ]) # AC_USE_SYSTEM_EXTENSIONS # ------------------------ # Enable extensions on systems that normally disable them, # typically due to standards-conformance issues. m4_ifndef([AC_USE_SYSTEM_EXTENSIONS],[ AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS], [AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl AC_BEFORE([$0], [AC_RUN_IFELSE])dnl AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=]) if test "$MINIX" = yes; then AC_DEFINE([_POSIX_SOURCE], [1], [Define to 1 if you need to in order for `stat' and other things to work.]) AC_DEFINE([_POSIX_1_SOURCE], [2], [Define to 2 if the system does not provide POSIX.1 features except with this defined.]) AC_DEFINE([_MINIX], [1], [Define to 1 if on MINIX.]) fi AH_VERBATIM([__EXTENSIONS__], [/* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif ]) AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__], [ac_cv_safe_to_define___extensions__], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[ # define __EXTENSIONS__ 1 ]AC_INCLUDES_DEFAULT])], [ac_cv_safe_to_define___extensions__=yes], [ac_cv_safe_to_define___extensions__=no])]) test $ac_cv_safe_to_define___extensions__ = yes && AC_DEFINE([__EXTENSIONS__]) AC_DEFINE([_ALL_SOURCE]) AC_DEFINE([_GNU_SOURCE]) AC_DEFINE([_POSIX_PTHREAD_SEMANTICS]) AC_DEFINE([_TANDEM_SOURCE]) ])# AC_USE_SYSTEM_EXTENSIONS ]) ctdb-2.5.1.dfsg/lib/replace/replace-test.h0000644000175000017500000000033712245023514020152 0ustar mathieumathieu#ifndef __LIB_REPLACE_REPLACE_TEST_H__ #define __LIB_REPLACE_REPLACE_TEST_H__ int libreplace_test_strptime(void); int test_readdir_os2_delete(void); int getifaddrs_test(void); #endif /* __LIB_REPLACE_REPLACE_TEST_H__ */ ctdb-2.5.1.dfsg/lib/replace/dlfcn.c0000644000175000017500000000354312245023514016645 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Samba system utilities Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jeremy Allison 1998-2002 Copyright (C) Jelmer Vernooij 2006 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include "replace.h" #ifdef HAVE_DL_H #include #endif #ifndef HAVE_DLOPEN #ifdef DLOPEN_TAKES_UNSIGNED_FLAGS void *rep_dlopen(const char *name, unsigned int flags) #else void *rep_dlopen(const char *name, int flags) #endif { #ifdef HAVE_SHL_LOAD if (name == NULL) return PROG_HANDLE; return (void *)shl_load(name, flags, 0); #else return NULL; #endif } #endif #ifndef HAVE_DLSYM void *rep_dlsym(void *handle, const char *symbol) { #ifdef HAVE_SHL_FINDSYM void *sym_addr; if (!shl_findsym((shl_t *)&handle, symbol, TYPE_UNDEFINED, &sym_addr)) return sym_addr; #endif return NULL; } #endif #ifndef HAVE_DLERROR char *rep_dlerror(void) { return "dynamic loading of objects not supported on this platform"; } #endif #ifndef HAVE_DLCLOSE int rep_dlclose(void *handle) { #ifdef HAVE_SHL_CLOSE return shl_unload((shl_t)handle); #else return 0; #endif } #endif ctdb-2.5.1.dfsg/lib/replace/crypt.m40000644000175000017500000000045212245023514017012 0ustar mathieumathieu############################################### # test for where we get crypt() from AC_CHECK_HEADERS(crypt.h) AC_SEARCH_LIBS_EXT(crypt, [crypt], CRYPT_LIBS, [ AC_DEFINE(HAVE_CRYPT,1,[Whether the system has the crypt() function]) ], [ LIBREPLACEOBJ="${LIBREPLACEOBJ} $libreplacedir/crypt.o" ]) ctdb-2.5.1.dfsg/lib/replace/repdir_getdents.c0000644000175000017500000001021312245023514020731 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Copyright (C) Andrew Tridgell 2005 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ /* a replacement for opendir/readdir/telldir/seekdir/closedir for BSD systems This is needed because the existing directory handling in FreeBSD and OpenBSD (and possibly NetBSD) doesn't correctly handle unlink() on files in a directory where telldir() has been used. On a block boundary it will occasionally miss a file when seekdir() is used to return to a position previously recorded with telldir(). This also fixes a severe performance and memory usage problem with telldir() on BSD systems. Each call to telldir() in BSD adds an entry to a linked list, and those entries are cleaned up on closedir(). This means with a large directory closedir() can take an arbitrary amount of time, causing network timeouts as millions of telldir() entries are freed Note! This replacement code is not portable. It relies on getdents() always leaving the file descriptor at a seek offset that is a multiple of DIR_BUF_SIZE. If the code detects that this doesn't happen then it will abort(). It also does not handle directories with offsets larger than can be stored in a long, This code is available under other free software licenses as well. Contact the author. */ #include #include #include #include #include #include #include #define DIR_BUF_BITS 9 #define DIR_BUF_SIZE (1<fd = open(dname, O_RDONLY); if (d->fd == -1) { free(d); return NULL; } if (fstat(d->fd, &sb) < 0) { close(d->fd); free(d); return NULL; } if (!S_ISDIR(sb.st_mode)) { close(d->fd); free(d); errno = ENOTDIR; return NULL; } d->ofs = 0; d->seekpos = 0; d->nbytes = 0; return (DIR *)d; } struct dirent *readdir(DIR *dir) { struct dir_buf *d = (struct dir_buf *)dir; struct dirent *de; if (d->ofs >= d->nbytes) { d->seekpos = lseek(d->fd, 0, SEEK_CUR); d->nbytes = getdents(d->fd, d->buf, DIR_BUF_SIZE); d->ofs = 0; } if (d->ofs >= d->nbytes) { return NULL; } de = (struct dirent *)&d->buf[d->ofs]; d->ofs += de->d_reclen; return de; } long telldir(DIR *dir) { struct dir_buf *d = (struct dir_buf *)dir; if (d->ofs >= d->nbytes) { d->seekpos = lseek(d->fd, 0, SEEK_CUR); d->ofs = 0; d->nbytes = 0; } /* this relies on seekpos always being a multiple of DIR_BUF_SIZE. Is that always true on BSD systems? */ if (d->seekpos & (DIR_BUF_SIZE-1)) { abort(); } return d->seekpos + d->ofs; } void seekdir(DIR *dir, long ofs) { struct dir_buf *d = (struct dir_buf *)dir; d->seekpos = lseek(d->fd, ofs & ~(DIR_BUF_SIZE-1), SEEK_SET); d->nbytes = getdents(d->fd, d->buf, DIR_BUF_SIZE); d->ofs = 0; while (d->ofs < (ofs & (DIR_BUF_SIZE-1))) { if (readdir(dir) == NULL) break; } } void rewinddir(DIR *dir) { seekdir(dir, 0); } int closedir(DIR *dir) { struct dir_buf *d = (struct dir_buf *)dir; int r = close(d->fd); if (r != 0) { return r; } free(d); return 0; } #ifndef dirfd /* darn, this is a macro on some systems. */ int dirfd(DIR *dir) { struct dir_buf *d = (struct dir_buf *)dir; return d->fd; } #endif ctdb-2.5.1.dfsg/lib/replace/hdr_replace.h0000644000175000017500000000012412245023514020024 0ustar mathieumathieu/* this is a replacement header for a missing system header */ #include "replace.h" ctdb-2.5.1.dfsg/lib/replace/repdir.m40000644000175000017500000000473212245023514017143 0ustar mathieumathieuAC_CACHE_CHECK([for broken readdir],libreplace_cv_READDIR_NEEDED,[ AC_TRY_RUN([ #define test_readdir_os2_delete main #include "$libreplacedir/test/os2_delete.c"], [libreplace_cv_READDIR_NEEDED=no], [libreplace_cv_READDIR_NEEDED=yes], [libreplace_cv_READDIR_NEEDED="assuming not"]) ]) AC_CHECK_FUNCS(dirfd) AC_HAVE_DECL(dirfd, [#include ]) # # try to replace with getdirentries() if needed # if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then AC_CHECK_FUNCS(getdirentries) AC_VERIFY_C_PROTOTYPE([long telldir(const DIR *dir)], [ return 0; ],[ AC_DEFINE(TELLDIR_TAKES_CONST_DIR, 1, [Whether telldir takes a const pointer]) ],[],[ #include ]) AC_VERIFY_C_PROTOTYPE([int seekdir(DIR *dir, long ofs)], [ return 0; ],[ AC_DEFINE(SEEKDIR_RETURNS_INT, 1, [Whether seekdir returns an int]) ],[],[ #include ]) AC_CACHE_CHECK([for replacing readdir using getdirentries()],libreplace_cv_READDIR_GETDIRENTRIES,[ AC_TRY_RUN([ #define _LIBREPLACE_REPLACE_H #include "$libreplacedir/repdir_getdirentries.c" #define test_readdir_os2_delete main #include "$libreplacedir/test/os2_delete.c"], [libreplace_cv_READDIR_GETDIRENTRIES=yes], [libreplace_cv_READDIR_GETDIRENTRIES=no]) ]) fi if test x"$libreplace_cv_READDIR_GETDIRENTRIES" = x"yes"; then AC_DEFINE(REPLACE_READDIR,1,[replace readdir]) AC_DEFINE(REPLACE_READDIR_GETDIRENTRIES,1,[replace readdir using getdirentries()]) LIBREPLACEOBJ="${LIBREPLACEOBJ} $libreplacedir/repdir_getdirentries.o" libreplace_cv_READDIR_NEEDED=no fi # # try to replace with getdents() if needed # if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then AC_CHECK_FUNCS(getdents) AC_CACHE_CHECK([for replacing readdir using getdents()],libreplace_cv_READDIR_GETDENTS,[ AC_TRY_RUN([ #define _LIBREPLACE_REPLACE_H #error _donot_use_getdents_replacement_anymore #include "$libreplacedir/repdir_getdents.c" #define test_readdir_os2_delete main #include "$libreplacedir/test/os2_delete.c"], [libreplace_cv_READDIR_GETDENTS=yes], [libreplace_cv_READDIR_GETDENTS=no]) ]) fi if test x"$libreplace_cv_READDIR_GETDENTS" = x"yes"; then AC_DEFINE(REPLACE_READDIR,1,[replace readdir]) AC_DEFINE(REPLACE_READDIR_GETDENTS,1,[replace readdir using getdents()]) LIBREPLACEOBJ="${LIBREPLACEOBJ} $libreplacedir/repdir_getdents.o" libreplace_cv_READDIR_NEEDED=no fi AC_MSG_CHECKING([a usable readdir()]) if test x"$libreplace_cv_READDIR_NEEDED" = x"yes"; then AC_MSG_RESULT(no) AC_MSG_WARN([the provided readdir() is broken]) else AC_MSG_RESULT(yes) fi ctdb-2.5.1.dfsg/lib/replace/win32_replace.h0000644000175000017500000001046412245023514020221 0ustar mathieumathieu#ifndef _WIN32_REPLACE_H #define _WIN32_REPLACE_H #ifdef HAVE_WINSOCK2_H #include #endif #ifdef HAVE_WS2TCPIP_H #include #endif #ifdef HAVE_WINDOWS_H #include #endif /* Map BSD Socket errorcodes to the WSA errorcodes (if possible) */ #define EAFNOSUPPORT WSAEAFNOSUPPORT #define ECONNREFUSED WSAECONNREFUSED #define EINPROGRESS WSAEINPROGRESS #define EMSGSIZE WSAEMSGSIZE #define ENOBUFS WSAENOBUFS #define ENOTSOCK WSAENOTSOCK #define ENETUNREACH WSAENETUNREACH #define ENOPROTOOPT WSAENOPROTOOPT #define ENOTCONN WSAENOTCONN #define ENOTSUP 134 /* We undefine the following constants due to conflicts with the w32api headers * and the Windows Platform SDK/DDK. */ #undef interface #undef ERROR_INVALID_PARAMETER #undef ERROR_INSUFFICIENT_BUFFER #undef ERROR_INVALID_DATATYPE #undef FILE_GENERIC_READ #undef FILE_GENERIC_WRITE #undef FILE_GENERIC_EXECUTE #undef FILE_ATTRIBUTE_READONLY #undef FILE_ATTRIBUTE_HIDDEN #undef FILE_ATTRIBUTE_SYSTEM #undef FILE_ATTRIBUTE_DIRECTORY #undef FILE_ATTRIBUTE_ARCHIVE #undef FILE_ATTRIBUTE_DEVICE #undef FILE_ATTRIBUTE_NORMAL #undef FILE_ATTRIBUTE_TEMPORARY #undef FILE_ATTRIBUTE_REPARSE_POINT #undef FILE_ATTRIBUTE_COMPRESSED #undef FILE_ATTRIBUTE_OFFLINE #undef FILE_ATTRIBUTE_ENCRYPTED #undef FILE_FLAG_WRITE_THROUGH #undef FILE_FLAG_NO_BUFFERING #undef FILE_FLAG_RANDOM_ACCESS #undef FILE_FLAG_SEQUENTIAL_SCAN #undef FILE_FLAG_DELETE_ON_CLOSE #undef FILE_FLAG_BACKUP_SEMANTICS #undef FILE_FLAG_POSIX_SEMANTICS #undef FILE_TYPE_DISK #undef FILE_TYPE_UNKNOWN #undef FILE_CASE_SENSITIVE_SEARCH #undef FILE_CASE_PRESERVED_NAMES #undef FILE_UNICODE_ON_DISK #undef FILE_PERSISTENT_ACLS #undef FILE_FILE_COMPRESSION #undef FILE_VOLUME_QUOTAS #undef FILE_VOLUME_IS_COMPRESSED #undef FILE_NOTIFY_CHANGE_FILE_NAME #undef FILE_NOTIFY_CHANGE_DIR_NAME #undef FILE_NOTIFY_CHANGE_ATTRIBUTES #undef FILE_NOTIFY_CHANGE_SIZE #undef FILE_NOTIFY_CHANGE_LAST_WRITE #undef FILE_NOTIFY_CHANGE_LAST_ACCESS #undef FILE_NOTIFY_CHANGE_CREATION #undef FILE_NOTIFY_CHANGE_EA #undef FILE_NOTIFY_CHANGE_SECURITY #undef FILE_NOTIFY_CHANGE_STREAM_NAME #undef FILE_NOTIFY_CHANGE_STREAM_SIZE #undef FILE_NOTIFY_CHANGE_STREAM_WRITE #undef FILE_NOTIFY_CHANGE_NAME #undef PRINTER_ATTRIBUTE_QUEUED #undef PRINTER_ATTRIBUTE_DIRECT #undef PRINTER_ATTRIBUTE_DEFAULT #undef PRINTER_ATTRIBUTE_SHARED #undef PRINTER_ATTRIBUTE_NETWORK #undef PRINTER_ATTRIBUTE_HIDDEN #undef PRINTER_ATTRIBUTE_LOCAL #undef PRINTER_ATTRIBUTE_ENABLE_DEVQ #undef PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS #undef PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST #undef PRINTER_ATTRIBUTE_WORK_OFFLINE #undef PRINTER_ATTRIBUTE_ENABLE_BIDI #undef PRINTER_ATTRIBUTE_RAW_ONLY #undef PRINTER_ATTRIBUTE_PUBLISHED #undef PRINTER_ENUM_DEFAULT #undef PRINTER_ENUM_LOCAL #undef PRINTER_ENUM_CONNECTIONS #undef PRINTER_ENUM_FAVORITE #undef PRINTER_ENUM_NAME #undef PRINTER_ENUM_REMOTE #undef PRINTER_ENUM_SHARED #undef PRINTER_ENUM_NETWORK #undef PRINTER_ENUM_EXPAND #undef PRINTER_ENUM_CONTAINER #undef PRINTER_ENUM_ICON1 #undef PRINTER_ENUM_ICON2 #undef PRINTER_ENUM_ICON3 #undef PRINTER_ENUM_ICON4 #undef PRINTER_ENUM_ICON5 #undef PRINTER_ENUM_ICON6 #undef PRINTER_ENUM_ICON7 #undef PRINTER_ENUM_ICON8 #undef PRINTER_STATUS_PAUSED #undef PRINTER_STATUS_ERROR #undef PRINTER_STATUS_PENDING_DELETION #undef PRINTER_STATUS_PAPER_JAM #undef PRINTER_STATUS_PAPER_OUT #undef PRINTER_STATUS_MANUAL_FEED #undef PRINTER_STATUS_PAPER_PROBLEM #undef PRINTER_STATUS_OFFLINE #undef PRINTER_STATUS_IO_ACTIVE #undef PRINTER_STATUS_BUSY #undef PRINTER_STATUS_PRINTING #undef PRINTER_STATUS_OUTPUT_BIN_FULL #undef PRINTER_STATUS_NOT_AVAILABLE #undef PRINTER_STATUS_WAITING #undef PRINTER_STATUS_PROCESSING #undef PRINTER_STATUS_INITIALIZING #undef PRINTER_STATUS_WARMING_UP #undef PRINTER_STATUS_TONER_LOW #undef PRINTER_STATUS_NO_TONER #undef PRINTER_STATUS_PAGE_PUNT #undef PRINTER_STATUS_USER_INTERVENTION #undef PRINTER_STATUS_OUT_OF_MEMORY #undef PRINTER_STATUS_DOOR_OPEN #undef PRINTER_STATUS_SERVER_UNKNOWN #undef PRINTER_STATUS_POWER_SAVE #undef DWORD #undef HKEY_CLASSES_ROOT #undef HKEY_CURRENT_USER #undef HKEY_LOCAL_MACHINE #undef HKEY_USERS #undef HKEY_PERFORMANCE_DATA #undef HKEY_CURRENT_CONFIG #undef HKEY_DYN_DATA #undef REG_DWORD #undef REG_QWORD #undef SERVICE_STATE_ALL #undef SE_GROUP_MANDATORY #undef SE_GROUP_ENABLED_BY_DEFAULT #undef SE_GROUP_ENABLED #endif /* _WIN32_REPLACE_H */ ctdb-2.5.1.dfsg/lib/replace/libreplace_ld.m40000644000175000017500000001332012245023514020430 0ustar mathieumathieu# # This offers a nice overview how to build shared libraries on all platforms # http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html # AC_DEFUN([AC_LIBREPLACE_STLD], [ AC_PATH_PROG(PROG_AR, ar) STLD=${PROG_AR} AC_SUBST(STLD) ]) AC_DEFUN([AC_LIBREPLACE_STLD_FLAGS], [ STLD_FLAGS="-rcs" AC_SUBST(STLD_FLAGS) ]) AC_DEFUN([AC_LD_EXPORT_DYNAMIC], [ saved_LDFLAGS="$LDFLAGS" if AC_TRY_COMMAND([${CC-cc} $CFLAGS -Wl,--version 2>&1 | grep "GNU ld" >/dev/null]); then LD_EXPORT_DYNAMIC="-Wl,-export-dynamic" else case "$host_os" in hpux* ) LD_EXPORT_DYNAMIC="-Wl,-E" ;; *) LD_EXPORT_DYNAMIC="" ;; esac fi AC_SUBST(LD_EXPORT_DYNAMIC) LDFLAGS="$saved_LDFLAGS" ]) AC_DEFUN([AC_LD_PICFLAG], [ case "$host_os" in *linux*|*gnu*) PICFLAG="-fPIC" ;; *solaris*) if test "${GCC}" = "yes"; then PICFLAG="-fPIC" else PICFLAG="-KPIC" fi ;; *sunos*) PICFLAG="-KPIC" # Is this correct for SunOS ;; *netbsd* | *freebsd* | *dragonfly* ) PICFLAG="-fPIC -DPIC" ;; *openbsd*) PICFLAG="-fPIC" ;; *irix*) if test "${GCC}" = "yes"; then PICFLAG="-fPIC" else PICFLAG="-KPIC" fi ;; *aix*) # as AIX code is always position independent... PICFLAG="-O2" ;; *hpux*) if test "${GCC}" = "yes"; then PICFLAG="-fPIC" elif test "$host_cpu" = "ia64"; then PICFLAG="+z" elif test $ac_cv_prog_cc_Ae = yes; then PICFLAG="+z +ESnolit" fi ;; *osf*) PICFLAG="-fPIC" ;; *unixware*) PICFLAG="-KPIC" ;; *darwin*) PICFLAG="-fno-common" ;; esac AC_SUBST(PICFLAG) ]) AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_LINKER], [ LD_SHLIB_LINKER="${CC}" case "$host_os" in *irix*) LD_SHLIB_LINKER="${PROG_LD}" ;; esac AC_SUBST(LD_SHLIB_LINKER) ]) AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_FLAGS], [ LD_SHLIB_FLAGS="-shared" case "$host_os" in *linux*|*gnu*) LD_SHLIB_FLAGS="-shared -Wl,-Bsymbolic" ;; *solaris*) LD_SHLIB_FLAGS="-G" if test "${GCC}" = "no"; then ## ${CFLAGS} added for building 64-bit shared ## libs using Sun's Compiler LD_SHLIB_FLAGS="-G \${CFLAGS}" fi ;; *sunos*) LD_SHLIB_FLAGS="-G" ;; *irix*) LD_SHLIB_FLAGS="-shared" ;; *aix*) LD_SHLIB_FLAGS="-Wl,-G,-bexpall,-bbigtoc" ;; *hpux*) if test "${GCC}" = "yes"; then LD_SHLIB_FLAGS="-shared" else LD_SHLIB_FLAGS="-b" fi ;; *osf*) LD_SHLIB_FLAGS="-shared" ;; *darwin*) LD_SHLIB_FLAGS="-dynamiclib -Wl,-search_paths_first" ;; esac AC_SUBST(LD_SHLIB_FLAGS) ]) AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_DISALLOW_UNDEF_FLAG], [ LD_SHLIB_DISALLOW_UNDEF_FLAG="" # # TODO: enforce error not only warnings # # NOTE: -Wl,--no-allow-shlib-undefined isn't what we want... # as it bails out on broken system libraries # case "$host_os" in *osf*) LD_SHLIB_DISALLOW_UNDEF_FLAG="-warning_unresolved" ;; *darwin*) LD_SHLIB_DISALLOW_UNDEF_FLAG="-undefined error" ;; esac AC_SUBST(LD_SHLIB_DISALLOW_UNDEF_FLAG) ]) AC_DEFUN([AC_LIBREPLACE_SHLD], [ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_LINKER]) SHLD="$LD_SHLIB_LINKER" AC_SUBST(SHLD) ]) AC_DEFUN([AC_LIBREPLACE_SHLD_FLAGS], [ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_FLAGS]) AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_DISALLOW_UNDEF_FLAG]) SHLD_FLAGS="$LD_SHLIB_FLAGS $LD_SHLIB_DISALLOW_UNDEF_FLAG" AC_SUBST(SHLD_FLAGS) ]) AC_DEFUN([AC_LD_SHLIBEXT], [ SHLIBEXT="so" case "$host_os" in *hpux*) if test "$host_cpu" = "ia64"; then SHLIBEXT="so" else SHLIBEXT="sl" fi ;; *darwin*) SHLIBEXT="dylib" ;; esac AC_SUBST(SHLIBEXT) ]) AC_DEFUN([AC_LD_SONAMEFLAG], [ AC_SUBST(SONAMEFLAG) SONAMEFLAG="" case "$host_os" in *linux*|*gnu*|*qnx*) SONAMEFLAG="-Wl,-soname=" ;; *solaris*) SONAMEFLAG="-h " if test "${GCC}" = "yes"; then SONAMEFLAG="-Wl,-soname=" fi ;; *sunos*) SONAMEFLAG="-Wl,-h," ;; *netbsd* | *freebsd* | *dragonfly* ) SONAMEFLAG="-Wl,-soname," ;; *openbsd*) SONAMEFLAG="-Wl,-soname," ;; *irix*) SONAMEFLAG="-Wl,-soname," ;; *hpux*) SONAMEFLAG="-Wl,+h," ;; *osf*) SONAMEFLAG="-Wl,-soname," ;; *unixware*) SONAMEFLAG="-Wl,-soname," ;; *darwin*) SONAMEFLAG="#" ;; *aix*) # Not supported SONAMEFLAG="#" ;; esac ]) AC_DEFUN([AC_LD_VERSIONSCRIPT], [ AC_SUBST(VERSIONSCRIPT) VERSIONSCRIPT="" case "$host_os" in *linux*|*gnu*) VERSIONSCRIPT="-Wl,--version-script" ;; *solaris*) if test "${GCC}" = "yes"; then VERSIONSCRIPT="-Wl,--version-script" fi ;; esac ]) AC_DEFUN([AC_LIBREPLACE_MDLD], [ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_LINKER]) MDLD="$LD_SHLIB_LINKER" AC_SUBST(MDLD) ]) AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG], [ LD_ALLOW_SHLIB_UNDEF_FLAG="" case "$host_os" in *linux*|*gnu*) LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,--allow-shlib-undefined" ;; *osf*) LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,-expect_unresolved,\"*\"" ;; *darwin*) LD_SHLIB_ALLOW_UNDEF_FLAG="-undefined dynamic_lookup" ;; *aix*) LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,-bnoentry" ;; esac AC_SUBST(LD_SHLIB_ALLOW_UNDEF_FLAG) ]) AC_DEFUN([AC_LIBREPLACE_MDLD_FLAGS], [ AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_FLAGS]) AC_REQUIRE([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG]) MDLD_FLAGS="$LD_SHLIB_FLAGS $LD_SHLIB_ALLOW_UNDEF_FLAG" AC_SUBST(MDLD_FLAGS) ]) AC_DEFUN([AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR], [ case "$host_os" in *linux*|*gnu*) LIB_PATH_VAR=LD_LIBRARY_PATH ;; *bsd*) LIB_PATH_VAR=LD_LIBRARY_PATH ;; *solaris*) LIB_PATH_VAR=LD_LIBRARY_PATH ;; *hpux*) LIB_PATH_VAR=SHLIB_PATH ;; *osf*) LIB_PATH_VAR=LD_LIBRARY_PATH ;; *aix*) LIB_PATH_VAR=LIBPATH ;; *irix*) LIB_PATH_VAR=LD_LIBRARY_PATH ;; *darwin*) LIB_PATH_VAR=DYLD_LIBRARY_PATH ;; *) LIB_PATH_VAR=LD_LIBRARY_PATH ;; esac AC_SUBST(LIB_PATH_VAR) ]) ctdb-2.5.1.dfsg/lib/replace/wscript0000644000175000017500000006751712245023514017044 0ustar mathieumathieu#!/usr/bin/env python APPNAME = 'libreplace' VERSION = '1.2.1' blddir = 'bin' import sys, os, Utils # find the buildtools directory srcdir = '.' while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5: srcdir = '../' + srcdir sys.path.insert(0, srcdir + '/buildtools/wafsamba') import wafsamba, samba_dist import Options, os, preproc samba_dist.DIST_DIRS('lib/replace buildtools:buildtools') def set_options(opt): opt.BUILTIN_DEFAULT('NONE') opt.PRIVATE_EXTENSION_DEFAULT('') opt.RECURSE('buildtools/wafsamba') @wafsamba.runonce def configure(conf): conf.RECURSE('buildtools/wafsamba') conf.env.standalone_replace = conf.IN_LAUNCH_DIR() conf.DEFINE('HAVE_LIBREPLACE', 1) conf.DEFINE('LIBREPLACE_NETWORK_CHECKS', 1) # on Tru64 certain features are only available with _OSF_SOURCE set to 1 # and _XOPEN_SOURCE set to 600 if conf.env['SYSTEM_UNAME_SYSNAME'] == 'OSF1': conf.DEFINE('_OSF_SOURCE', 1, add_to_cflags=True) conf.DEFINE('_XOPEN_SOURCE', 600, add_to_cflags=True) # SCM_RIGHTS is only avail if _XOPEN_SOURCE iѕ defined on IRIX if conf.env['SYSTEM_UNAME_SYSNAME'] == 'IRIX': conf.DEFINE('_XOPEN_SOURCE', 600, add_to_cflags=True) conf.DEFINE('_BSD_TYPES', 1, add_to_cflags=True) # Try to find the right extra flags for C99 initialisers for f in ["", "-AC99", "-qlanglvl=extc99", "-qlanglvl=stdc99", "-c99"]: if conf.CHECK_CFLAGS([f], ''' struct foo {int x;char y;}; struct foo bar = { .y = 'X', .x = 1 }; '''): if f != "": conf.ADD_CFLAGS(f) break if conf.CHECK_CFLAGS(['-fstack-protector']) and conf.CHECK_LDFLAGS(['-fstack-protector']): conf.ADD_CFLAGS('-fstack-protector') conf.ADD_LDFLAGS('-fstack-protector') # Try to find the right extra flags for -Werror behaviour for f in ["-Werror", # GCC "-errwarn=%all", # Sun Studio "-qhalt=w", # IBM xlc "-w2", # Tru64 ]: if conf.CHECK_CFLAGS([f], ''' '''): if not 'WERROR_CFLAGS' in conf.env: conf.env['WERROR_CFLAGS'] = [] conf.env['WERROR_CFLAGS'].extend([f]) break conf.CHECK_HEADERS('linux/types.h crypt.h locale.h acl/libacl.h compat.h') conf.CHECK_HEADERS('acl/libacl.h attr/xattr.h compat.h ctype.h dustat.h') conf.CHECK_HEADERS('fcntl.h fnmatch.h glob.h history.h krb5.h langinfo.h') conf.CHECK_HEADERS('libaio.h locale.h ndir.h pwd.h') conf.CHECK_HEADERS('shadow.h sys/acl.h') conf.CHECK_HEADERS('sys/attributes.h attr/attributes.h sys/capability.h sys/dir.h sys/epoll.h') conf.CHECK_HEADERS('sys/fcntl.h sys/filio.h sys/filsys.h sys/fs/s5param.h sys/fs/vx/quota.h') conf.CHECK_HEADERS('sys/id.h sys/ioctl.h sys/ipc.h sys/mman.h sys/mode.h sys/ndir.h sys/priv.h') conf.CHECK_HEADERS('sys/resource.h sys/security.h sys/shm.h sys/statfs.h sys/statvfs.h sys/termio.h') conf.CHECK_HEADERS('sys/vfs.h sys/xattr.h termio.h termios.h sys/file.h') conf.CHECK_HEADERS('sys/ucontext.h sys/wait.h sys/stat.h malloc.h grp.h') conf.CHECK_HEADERS('sys/select.h setjmp.h utime.h sys/syslog.h syslog.h') conf.CHECK_HEADERS('stdarg.h vararg.h sys/mount.h mntent.h') conf.CHECK_HEADERS('stropts.h unix.h string.h strings.h sys/param.h limits.h') conf.CHECK_HEADERS('''sys/socket.h netinet/in.h netdb.h arpa/inet.h netinet/in_systm.h netinet/ip.h netinet/tcp.h netinet/in_ip.h sys/sockio.h sys/un.h''', together=True) conf.CHECK_HEADERS('sys/uio.h ifaddrs.h direct.h dirent.h') conf.CHECK_HEADERS('windows.h winsock2.h ws2tcpip.h') conf.CHECK_HEADERS('libintl.h errno.h') conf.CHECK_HEADERS('gcrypt.h getopt.h iconv.h') conf.CHECK_HEADERS('sys/inotify.h memory.h nss.h sasl/sasl.h') conf.CHECK_HEADERS('security/pam_appl.h zlib.h asm/unistd.h') conf.CHECK_HEADERS('aio.h sys/unistd.h rpc/rpc.h rpc/nettype.h alloca.h float.h') conf.CHECK_HEADERS('rpcsvc/nis.h rpcsvc/ypclnt.h sys/sysctl.h') conf.CHECK_HEADERS('sys/fileio.h sys/filesys.h sys/dustat.h sys/sysmacros.h') conf.CHECK_HEADERS('xfs/libxfs.h netgroup.h') conf.CHECK_CODE('', headers='rpc/rpc.h rpcsvc/yp_prot.h', define='HAVE_RPCSVC_YP_PROT_H') conf.CHECK_HEADERS('valgrind.h valgrind/valgrind.h valgrind/memcheck.h') conf.CHECK_HEADERS('nss_common.h nsswitch.h ns_api.h') conf.CHECK_HEADERS('sys/extattr.h sys/ea.h sys/proplist.h sys/cdefs.h') conf.CHECK_HEADERS('utmp.h utmpx.h lastlog.h malloc.h') conf.CHECK_HEADERS('syscall.h sys/syscall.h inttypes.h') # Check for process set name support conf.CHECK_CODE(''' #include int main(void) { prctl(0); return 0; } ''', 'HAVE_PRCTL', headers='sys/prctl.h', msg='Checking for prctl syscall') conf.CHECK_CODE(''' #include #ifdef HAVE_FCNTL_H #include #endif int main(void) { int fd = open("/dev/null", O_DIRECT); } ''', define='HAVE_OPEN_O_DIRECT', addmain=False, msg='Checking for O_DIRECT flag to open(2)') conf.CHECK_TYPES('"long long" intptr_t uintptr_t ptrdiff_t comparison_fn_t') conf.CHECK_TYPE('_Bool', define='HAVE__Bool') conf.CHECK_TYPE('bool', define='HAVE_BOOL') conf.CHECK_TYPE('int8_t', 'char') conf.CHECK_TYPE('uint8_t', 'unsigned char') conf.CHECK_TYPE('int16_t', 'short') conf.CHECK_TYPE('uint16_t', 'unsigned short') conf.CHECK_TYPE('int32_t', 'int') conf.CHECK_TYPE('uint32_t', 'unsigned') conf.CHECK_TYPE('int64_t', 'long long') conf.CHECK_TYPE('uint64_t', 'unsigned long long') conf.CHECK_TYPE('size_t', 'unsigned int') conf.CHECK_TYPE('ssize_t', 'int') conf.CHECK_TYPE('ino_t', 'unsigned') conf.CHECK_TYPE('loff_t', 'off_t') conf.CHECK_TYPE('offset_t', 'loff_t') conf.CHECK_TYPE('volatile int', define='HAVE_VOLATILE') conf.CHECK_TYPE('uint_t', 'unsigned int') conf.CHECK_TYPE('blksize_t', 'long', headers='sys/types.h sys/stat.h unistd.h') conf.CHECK_TYPE('blkcnt_t', 'long', headers='sys/types.h sys/stat.h unistd.h') conf.CHECK_SIZEOF('bool char int "long long" long short size_t ssize_t') conf.CHECK_SIZEOF('int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t') conf.CHECK_SIZEOF('void*', define='SIZEOF_VOID_P') conf.CHECK_SIZEOF('off_t dev_t ino_t time_t') conf.CHECK_TYPES('socklen_t', headers='sys/socket.h') conf.CHECK_TYPE_IN('struct ifaddrs', 'ifaddrs.h') conf.CHECK_TYPE_IN('struct addrinfo', 'netdb.h') conf.CHECK_TYPE_IN('struct sockaddr', 'sys/socket.h') conf.CHECK_CODE('struct sockaddr_in6 x', define='HAVE_STRUCT_SOCKADDR_IN6', headers='sys/socket.h netdb.h netinet/in.h') conf.CHECK_TYPE_IN('struct sockaddr_storage', 'sys/socket.h') conf.CHECK_TYPE_IN('sa_family_t', 'sys/socket.h') conf.CHECK_TYPE_IN('sig_atomic_t', 'signal.h', define='HAVE_SIG_ATOMIC_T_TYPE') conf.CHECK_FUNCS_IN('''inet_ntoa inet_aton inet_ntop inet_pton connect gethostbyname getaddrinfo getnameinfo freeaddrinfo gai_strerror socketpair''', 'socket nsl', checklibc=True, headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h') # Some old Linux systems have broken header files and # miss the IPV6_V6ONLY define in netinet/in.h, # but have it in linux/in6.h. # We can't include both files so we just check if the value # if defined and do the replacement in system/network.h if not conf.CHECK_VARIABLE('IPV6_V6ONLY', headers='sys/socket.h netdb.h netinet/in.h'): conf.CHECK_CODE(''' #include #if (IPV6_V6ONLY != 26) #error no IPV6_V6ONLY support on linux #endif int main(void) { return IPV6_V6ONLY; } ''', define='HAVE_LINUX_IPV6_V6ONLY_26', addmain=False, msg='Checking for IPV6_V6ONLY in linux/in6.h', local_include=False) conf.CHECK_CODE(''' struct sockaddr_storage sa_store; struct addrinfo *ai = NULL; struct in6_addr in6addr; int idx = if_nametoindex("iface1"); int s = socket(AF_INET6, SOCK_STREAM, 0); int ret = getaddrinfo(NULL, NULL, NULL, &ai); if (ret != 0) { const char *es = gai_strerror(ret); } freeaddrinfo(ai); { int val = 1; #ifdef HAVE_LINUX_IPV6_V6ONLY_26 #define IPV6_V6ONLY 26 #endif ret = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&val, sizeof(val)); } ''', define='HAVE_IPV6', lib='nsl socket', headers='sys/socket.h netdb.h netinet/in.h') if conf.CONFIG_SET('HAVE_SYS_UCONTEXT_H') and conf.CONFIG_SET('HAVE_SIGNAL_H'): conf.CHECK_CODE(''' ucontext_t uc; sigaddset(&uc.uc_sigmask, SIGUSR1); ''', 'HAVE_UCONTEXT_T', msg="Checking whether we have ucontext_t", headers='signal.h sys/ucontext.h') # these may be builtins, so we need the link=False strategy conf.CHECK_FUNCS('strdup memmem printf memset memcpy memmove strcpy strncpy bzero', link=False) # See https://bugzilla.samba.org/show_bug.cgi?id=1097 # # Ported in from autoconf where it was added with this commit: # commit 804cfb20a067b4b687089dc72a8271b3abf20f31 # Author: Simo Sorce # Date: Wed Aug 25 14:24:16 2004 +0000 # r2070: Let's try to overload srnlen and strndup for AIX where they are natly broken. host_os = sys.platform if host_os.rfind('aix') > -1: conf.DEFINE('BROKEN_STRNLEN', 1) conf.DEFINE('BROKEN_STRNDUP', 1) conf.CHECK_FUNCS('shl_load shl_unload shl_findsym') conf.CHECK_FUNCS('pipe strftime srandom random srand rand usleep setbuffer') conf.CHECK_FUNCS('lstat getpgrp utime utimes setuid seteuid setreuid setresuid setgid setegid') conf.CHECK_FUNCS('setregid setresgid chroot strerror vsyslog setlinebuf mktime') conf.CHECK_FUNCS('ftruncate chsize rename waitpid wait4') conf.CHECK_FUNCS('initgroups pread pwrite strndup strcasestr') conf.CHECK_FUNCS('strtok_r mkdtemp dup2 dprintf vdprintf isatty chown lchown') conf.CHECK_FUNCS('link readlink symlink realpath snprintf vsnprintf') conf.CHECK_FUNCS('asprintf vasprintf setenv unsetenv strnlen strtoull __strtoull') conf.CHECK_FUNCS('strtouq strtoll __strtoll strtoq memalign posix_memalign') conf.CHECK_FUNCS('prctl') # libbsd on some platforms provides strlcpy and strlcat if not conf.CHECK_FUNCS('strlcpy strlcat'): conf.CHECK_FUNCS_IN('strlcpy strlcat', 'bsd', headers='bsd/string.h', checklibc=True) if not conf.CHECK_FUNCS('getpeereid'): conf.CHECK_FUNCS_IN('getpeereid', 'bsd', headers='sys/types.h bsd/unistd.h') if not conf.CHECK_FUNCS_IN('setproctitle', 'bsd', headers='sys/types.h bsd/unistd.h'): conf.CHECK_FUNCS_IN('setproctitle', 'setproctitle', headers='setproctitle.h') conf.CHECK_CODE(''' struct ucred cred; socklen_t cred_len; int ret = getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len);''', 'HAVE_PEERCRED', msg="Checking whether we can use SO_PEERCRED to get socket credentials", headers='sys/types.h sys/socket.h') #Some OS (ie. freebsd) return EINVAL if the convertion could not be done, it's not what we expect #Let's detect those cases if conf.CONFIG_SET('HAVE_STRTOLL'): conf.CHECK_CODE(''' long long nb = strtoll("Text", NULL, 0); if (errno == EINVAL) { return 0; } else { return 1; } ''', msg="Checking correct behavior of strtoll", headers = 'errno.h', execute = True, define = 'HAVE_BSD_STRTOLL', ) conf.CHECK_FUNCS('if_nametoindex strerror_r') conf.CHECK_FUNCS('getdirentries getdents syslog') conf.CHECK_FUNCS('gai_strerror get_current_dir_name') conf.CHECK_FUNCS('timegm getifaddrs freeifaddrs mmap setgroups syscall setsid') conf.CHECK_FUNCS('getgrent_r getgrgid_r getgrnam_r getgrouplist getpagesize') conf.CHECK_FUNCS('getpwent_r getpwnam_r getpwuid_r epoll_create') conf.SET_TARGET_TYPE('attr', 'EMPTY') xattr_headers='sys/attributes.h attr/xattr.h sys/xattr.h' conf.CHECK_FUNCS_IN(''' fgetxattr flistea flistxattr fremovexattr fsetxattr getxattr listxattr removexattr setxattr ''', 'attr', checklibc=True, headers=xattr_headers) # We need to check for linux xattrs first, as we do not wish to link to -lattr # (the XFS compat API) on Linux systems with the native xattr API if not conf.CONFIG_SET('HAVE_GETXATTR'): conf.CHECK_FUNCS_IN(''' attr_get attr_getf attr_list attr_listf attropen attr_remove attr_removef attr_set attr_setf extattr_delete_fd extattr_delete_file extattr_get_fd extattr_get_file extattr_list_fd extattr_list_file extattr_set_fd extattr_set_file fgetea fremoveea fsetea getea listea removeea setea ''', 'attr', checklibc=True, headers=xattr_headers) if (conf.CONFIG_SET('HAVE_ATTR_LISTF') or conf.CONFIG_SET('HAVE_EXTATTR_LIST_FD') or conf.CONFIG_SET('HAVE_FLISTEA') or conf.CONFIG_SET('HAVE_FLISTXATTR')): conf.DEFINE('HAVE_XATTR_SUPPORT', 1) # Darwin has extra options to xattr-family functions conf.CHECK_CODE('getxattr(NULL, NULL, NULL, 0, 0, 0)', headers=xattr_headers, local_include=False, define='XATTR_ADDITIONAL_OPTIONS', msg="Checking whether xattr interface takes additional options") conf.CHECK_FUNCS_IN('dlopen dlsym dlerror dlclose', 'dl', checklibc=True, headers='dlfcn.h dl.h') conf.CHECK_C_PROTOTYPE('dlopen', 'void *dlopen(const char* filename, unsigned int flags)', define='DLOPEN_TAKES_UNSIGNED_FLAGS', headers='dlfcn.h dl.h') if conf.CHECK_FUNCS_IN('fdatasync', 'rt', checklibc=True): # some systems are missing the declaration conf.CHECK_DECLS('fdatasync') if conf.CHECK_FUNCS_IN('clock_gettime', 'rt', checklibc=True): for c in ['CLOCK_MONOTONIC', 'CLOCK_PROCESS_CPUTIME_ID', 'CLOCK_REALTIME']: conf.CHECK_CODE(''' #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif clockid_t clk = %s''' % c, 'HAVE_%s' % c, msg='Checking whether the clock_gettime clock ID %s is available' % c) conf.CHECK_TYPE('struct timespec', headers='sys/time.h time.h') # these headers need to be tested as a group on freebsd conf.CHECK_HEADERS(headers='sys/socket.h net/if.h', together=True) conf.CHECK_HEADERS(headers='netinet/in.h arpa/nameser.h resolv.h', together=True) conf.CHECK_FUNCS_IN('res_search', 'resolv', checklibc=True, headers='netinet/in.h arpa/nameser.h resolv.h') if not conf.CHECK_FUNCS_IN('gettext', 'intl', checklibc=True, headers='libintl.h'): # Some hosts need lib iconv for linking with lib intl # So we try with flags just in case it helps. oldflags = conf.env['LDFLAGS_INTL'] conf.env['LDFLAGS_INTL'] = "-liconv" if not conf.CHECK_LIB('intl'): conf.env['LDFLAGS_INTL'] = oldflags else: conf.CHECK_FUNCS_IN('gettext', 'intl', checklibc=True, headers='libintl.h') conf.CHECK_FUNCS_IN('dgettext gettext', 'intl', headers='libintl.h') conf.CHECK_FUNCS_IN('pthread_create', 'pthread', checklibc=True, headers='pthread.h') conf.CHECK_FUNCS_IN('crypt', 'crypt', checklibc=True) conf.CHECK_VARIABLE('rl_event_hook', define='HAVE_DECL_RL_EVENT_HOOK', always=True, headers='readline.h readline/readline.h readline/history.h') conf.CHECK_DECLS('snprintf vsnprintf asprintf vasprintf') conf.CHECK_DECLS('errno', headers='errno.h', reverse=True) conf.CHECK_DECLS('environ getgrent_r getpwent_r', reverse=True, headers='pwd.h grp.h') conf.CHECK_DECLS('pread pwrite setenv setresgid setresuid', reverse=True) if conf.CONFIG_SET('HAVE_EPOLL_CREATE') and conf.CONFIG_SET('HAVE_SYS_EPOLL_H'): conf.DEFINE('HAVE_EPOLL', 1) conf.CHECK_HEADERS('poll.h') conf.CHECK_FUNCS('poll') conf.CHECK_FUNCS('strptime') conf.CHECK_DECLS('strptime', headers='time.h') conf.CHECK_CODE('''#define LIBREPLACE_CONFIGURE_TEST_STRPTIME #include "test/strptime.c"''', define='HAVE_WORKING_STRPTIME', execute=True, addmain=False, msg='Checking for working strptime') conf.CHECK_CODE('gettimeofday(NULL, NULL)', 'HAVE_GETTIMEOFDAY_TZ', execute=False) conf.CHECK_CODE('#include "test/snprintf.c"', define="HAVE_C99_VSNPRINTF", execute=True, addmain=False, msg="Checking for C99 vsnprintf") conf.CHECK_CODE('#include "test/shared_mmap.c"', addmain=False, add_headers=False, execute=True, define='HAVE_SHARED_MMAP', msg="Checking for HAVE_SHARED_MMAP") conf.CHECK_CODE('#include "test/shared_mremap.c"', addmain=False, add_headers=False, execute=True, define='HAVE_MREMAP', msg="Checking for HAVE_MREMAP") # OpenBSD (and I've heard HPUX) doesn't sync between mmap and write. # FIXME: Anything other than a 0 or 1 exit code should abort configure! conf.CHECK_CODE('#include "test/incoherent_mmap.c"', addmain=False, add_headers=False, execute=True, define='HAVE_INCOHERENT_MMAP', msg="Checking for HAVE_INCOHERENT_MMAP") conf.SAMBA_BUILD_ENV() conf.CHECK_CODE(''' typedef struct {unsigned x;} FOOBAR; #define X_FOOBAR(x) ((FOOBAR) { x }) #define FOO_ONE X_FOOBAR(1) FOOBAR f = FOO_ONE; static const struct { FOOBAR y; } f2[] = { {FOO_ONE} }; static const FOOBAR f3[] = {FOO_ONE}; ''', define='HAVE_IMMEDIATE_STRUCTURES') conf.CHECK_CODE('mkdir("foo",0777)', define='HAVE_MKDIR_MODE', headers='sys/stat.h') conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_mtim.tv_nsec', define='HAVE_STAT_TV_NSEC', headers='sys/stat.h') # we need the st_rdev test under two names conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_rdev', define='HAVE_STRUCT_STAT_ST_RDEV', headers='sys/stat.h') conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_rdev', define='HAVE_ST_RDEV', headers='sys/stat.h') conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_storage', 'ss_family', headers='sys/socket.h netinet/in.h') conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_storage', '__ss_family', headers='sys/socket.h netinet/in.h') if conf.CHECK_STRUCTURE_MEMBER('struct sockaddr', 'sa_len', headers='sys/socket.h netinet/in.h', define='HAVE_SOCKADDR_SA_LEN'): # the old build system produced both defines conf.DEFINE('HAVE_STRUCT_SOCKADDR_SA_LEN', 1) conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_in', 'sin_len', headers='sys/socket.h netinet/in.h', define='HAVE_SOCK_SIN_LEN') conf.CHECK_CODE('struct sockaddr_un sunaddr; sunaddr.sun_family = AF_UNIX;', define='HAVE_UNIXSOCKET', headers='sys/socket.h sys/un.h') conf.CHECK_CODE(''' struct stat st; char tpl[20]="/tmp/test.XXXXXX"; char tpl2[20]="/tmp/test.XXXXXX"; int fd = mkstemp(tpl); int fd2 = mkstemp(tpl2); if (fd == -1) { if (fd2 != -1) { unlink(tpl2); } exit(1); } if (fd2 == -1) exit(1); unlink(tpl); unlink(tpl2); if (fstat(fd, &st) != 0) exit(1); if ((st.st_mode & 0777) != 0600) exit(1); if (strcmp(tpl, "/tmp/test.XXXXXX") == 0) { exit(1); } if (strcmp(tpl, tpl2) == 0) { exit(1); } exit(0); ''', define='HAVE_SECURE_MKSTEMP', execute=True, mandatory=True) # lets see if we get a mandatory failure for this one if conf.CHECK_CFLAGS('-fvisibility=hidden'): conf.env.VISIBILITY_CFLAGS = '-fvisibility=hidden' conf.CHECK_CODE('''void vis_foo1(void) {} __attribute__((visibility("default"))) void vis_foo2(void) {}''', cflags=conf.env.VISIBILITY_CFLAGS, define='HAVE_VISIBILITY_ATTR') # look for a method of finding the list of network interfaces for method in ['HAVE_IFACE_GETIFADDRS', 'HAVE_IFACE_AIX', 'HAVE_IFACE_IFCONF', 'HAVE_IFACE_IFREQ']: if conf.CHECK_CODE(''' #define %s 1 #define NO_CONFIG_H 1 #define AUTOCONF_TEST 1 #define SOCKET_WRAPPER_NOT_REPLACE #include "replace.c" #include "inet_ntop.c" #include "snprintf.c" #include "getifaddrs.c" #define getifaddrs_test main #include "test/getifaddrs.c" ''' % method, method, lib='nsl socket', addmain=False, execute=True): break conf.RECURSE('system') conf.SAMBA_CONFIG_H() REPLACEMENT_FUNCTIONS = { 'replace.c': ['ftruncate', 'strlcpy', 'strlcat', 'mktime', 'initgroups', 'memmove', 'strdup', 'setlinebuf', 'vsyslog', 'strnlen', 'strndup', 'waitpid', 'seteuid', 'setegid', 'chroot', 'mkstemp', 'mkdtemp', 'pread', 'pwrite', 'strcasestr', 'strtok_r', 'strtoll', 'strtoull', 'setenv', 'unsetenv', 'utime', 'utimes', 'dup2', 'chown', 'link', 'readlink', 'symlink', 'lchown', 'realpath', 'memmem', 'vdprintf', 'dprintf', 'get_current_dir_name', 'strerror_r', 'clock_gettime'], 'timegm.c': ['timegm'], # Note: C99_VSNPRINTF is not a function, but a special condition # for replacement 'snprintf.c': ['C99_VSNPRINTF', 'snprintf', 'vsnprintf', 'asprintf', 'vasprintf'], # Note: WORKING_STRPTIME is not a function, but a special condition # for replacement 'strptime.c': ['WORKING_STRPTIME', 'strptime'], } def build(bld): bld.RECURSE('buildtools/wafsamba') REPLACE_HOSTCC_SOURCE = '' for filename, functions in REPLACEMENT_FUNCTIONS.iteritems(): for function in functions: if not bld.CONFIG_SET('HAVE_%s' % function.upper()): REPLACE_HOSTCC_SOURCE += ' %s' % filename break extra_libs = '' if bld.CONFIG_SET('HAVE_LIBBSD'): extra_libs += ' bsd' bld.SAMBA_SUBSYSTEM('LIBREPLACE_HOSTCC', REPLACE_HOSTCC_SOURCE, use_hostcc=True, use_global_deps=False, cflags='-DSOCKET_WRAPPER_DISABLE=1 -DNSS_WRAPPER_DISABLE=1 -DUID_WRAPPER_DISABLE=1 -D_SAMBA_HOSTCC_', group='compiler_libraries', deps = extra_libs ) REPLACE_SOURCE = REPLACE_HOSTCC_SOURCE if not bld.CONFIG_SET('HAVE_CRYPT'): REPLACE_SOURCE += ' crypt.c' if not bld.CONFIG_SET('HAVE_DLOPEN'): REPLACE_SOURCE += ' dlfcn.c' if not bld.CONFIG_SET('HAVE_POLL'): REPLACE_SOURCE += ' poll.c' if not bld.CONFIG_SET('HAVE_SOCKETPAIR'): REPLACE_SOURCE += ' socketpair.c' if not bld.CONFIG_SET('HAVE_CONNECT'): REPLACE_SOURCE += ' socket.c' if not bld.CONFIG_SET('HAVE_GETIFADDRS'): REPLACE_SOURCE += ' getifaddrs.c' if not bld.CONFIG_SET('HAVE_GETADDRINFO'): REPLACE_SOURCE += ' getaddrinfo.c' if not bld.CONFIG_SET('HAVE_INET_NTOA'): REPLACE_SOURCE += ' inet_ntoa.c' if not bld.CONFIG_SET('HAVE_INET_ATON'): REPLACE_SOURCE += ' inet_aton.c' if not bld.CONFIG_SET('HAVE_INET_NTOP'): REPLACE_SOURCE += ' inet_ntop.c' if not bld.CONFIG_SET('HAVE_INET_PTON'): REPLACE_SOURCE += ' inet_pton.c' if not bld.CONFIG_SET('HAVE_GETXATTR') or bld.CONFIG_SET('XATTR_ADDITIONAL_OPTIONS'): REPLACE_SOURCE += ' xattr.c' bld.SAMBA_LIBRARY('replace', source=REPLACE_SOURCE, group='base_libraries', # FIXME: Ideally symbols should be hidden here so they # don't appear in the global namespace when Samba # libraries are loaded, but this doesn't appear to work # at the moment: # hide_symbols=bld.BUILTIN_LIBRARY('replace'), private_library=True, deps='crypt dl nsl socket rt attr' + extra_libs) bld.SAMBA_SUBSYSTEM('replace-test', source='''test/testsuite.c test/strptime.c test/os2_delete.c test/getifaddrs.c''', deps='replace') if bld.env.standalone_replace: bld.SAMBA_BINARY('replace_testsuite', source='test/main.c', deps='replace replace-test', install=False) # build replacements for stdint.h and stdbool.h if needed bld.SAMBA_GENERATOR('replace_stdint_h', rule='cp ${SRC} ${TGT}', source='hdr_replace.h', target='stdint.h', enabled = not bld.CONFIG_SET('HAVE_STDINT_H')) bld.SAMBA_GENERATOR('replace_stdbool_h', rule='cp ${SRC} ${TGT}', source='hdr_replace.h', target='stdbool.h', enabled = not bld.CONFIG_SET('HAVE_STDBOOL_H')) def dist(): '''makes a tarball for distribution''' samba_dist.dist() ctdb-2.5.1.dfsg/lib/replace/crypt.c0000644000175000017500000005346112245023514016724 0ustar mathieumathieu/* This bit of code was derived from the UFC-crypt package which carries the following copyright Modified for use by Samba by Andrew Tridgell, October 1994 Note that this routine is only faster on some machines. Under Linux 1.1.51 libc 4.5.26 I actually found this routine to be slightly slower. Under SunOS I found a huge speedup by using these routines (a factor of 20 or so) Warning: I've had a report from Steve Kennedy that this crypt routine may sometimes get the wrong answer. Only use UFC_CRYT if you really need it. */ #include "replace.h" #ifndef HAVE_CRYPT /* * UFC-crypt: ultra fast crypt(3) implementation * * Copyright (C) 1991-1998, Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . * * @(#)crypt_util.c 2.31 02/08/92 * * Support routines * */ #ifndef long32 #define long32 int32_t #endif #ifndef long64 #define long64 int64_t #endif #ifndef ufc_long #define ufc_long unsigned #endif #ifndef _UFC_64_ #define _UFC_32_ #endif /* * Permutation done once on the 56 bit * key derived from the original 8 byte ASCII key. */ static int pc1[56] = { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 }; /* * How much to rotate each 28 bit half of the pc1 permutated * 56 bit key before using pc2 to give the i' key */ static int rots[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; /* * Permutation giving the key * of the i' DES round */ static int pc2[48] = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 }; /* * The E expansion table which selects * bits from the 32 bit intermediate result. */ static int esel[48] = { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 }; static int e_inverse[64]; /* * Permutation done on the * result of sbox lookups */ static int perm32[32] = { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 }; /* * The sboxes */ static int sbox[8][4][16]= { { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 }, { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 }, { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 }, { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } }, { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 }, { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 }, { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 }, { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } }, { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 }, { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 }, { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 }, { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } }, { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 }, { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 }, { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 }, { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } }, { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 }, { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 }, { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 }, { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } }, { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 }, { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 }, { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 }, { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } }, { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 }, { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 }, { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 }, { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } }, { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 }, { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 }, { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 }, { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } } }; /* * This is the final * permutation matrix */ static int final_perm[64] = { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 }; /* * The 16 DES keys in BITMASK format */ #ifdef _UFC_32_ long32 _ufc_keytab[16][2]; #endif #ifdef _UFC_64_ long64 _ufc_keytab[16]; #endif #define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') /* Macro to set a bit (0..23) */ #define BITMASK(i) ( (1<<(11-(i)%12+3)) << ((i)<12?16:0) ) /* * sb arrays: * * Workhorses of the inner loop of the DES implementation. * They do sbox lookup, shifting of this value, 32 bit * permutation and E permutation for the next round. * * Kept in 'BITMASK' format. */ #ifdef _UFC_32_ long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192]; static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; #endif #ifdef _UFC_64_ long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096]; static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; #endif /* * eperm32tab: do 32 bit permutation and E selection * * The first index is the byte number in the 32 bit value to be permuted * - second - is the value of this byte * - third - selects the two 32 bit values * * The table is used and generated internally in init_des to speed it up */ static ufc_long eperm32tab[4][256][2]; /* * do_pc1: permform pc1 permutation in the key schedule generation. * * The first index is the byte number in the 8 byte ASCII key * - second - - the two 28 bits halfs of the result * - third - selects the 7 bits actually used of each byte * * The result is kept with 28 bit per 32 bit with the 4 most significant * bits zero. */ static ufc_long do_pc1[8][2][128]; /* * do_pc2: permform pc2 permutation in the key schedule generation. * * The first index is the septet number in the two 28 bit intermediate values * - second - - - septet values * * Knowledge of the structure of the pc2 permutation is used. * * The result is kept with 28 bit per 32 bit with the 4 most significant * bits zero. */ static ufc_long do_pc2[8][128]; /* * efp: undo an extra e selection and do final * permutation giving the DES result. * * Invoked 6 bit a time on two 48 bit values * giving two 32 bit longs. */ static ufc_long efp[16][64][2]; static unsigned char bytemask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; static ufc_long longmask[32] = { 0x80000000, 0x40000000, 0x20000000, 0x10000000, 0x08000000, 0x04000000, 0x02000000, 0x01000000, 0x00800000, 0x00400000, 0x00200000, 0x00100000, 0x00080000, 0x00040000, 0x00020000, 0x00010000, 0x00008000, 0x00004000, 0x00002000, 0x00001000, 0x00000800, 0x00000400, 0x00000200, 0x00000100, 0x00000080, 0x00000040, 0x00000020, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000001 }; /* * Silly rewrite of 'bzero'. I do so * because some machines don't have * bzero and some don't have memset. */ static void clearmem(char *start, int cnt) { while(cnt--) *start++ = '\0'; } static int initialized = 0; /* lookup a 6 bit value in sbox */ #define s_lookup(i,s) sbox[(i)][(((s)>>4) & 0x2)|((s) & 0x1)][((s)>>1) & 0xf]; /* * Initialize unit - may be invoked directly * by fcrypt users. */ static void ufc_init_des(void) { int comes_from_bit; int bit, sg; ufc_long j; ufc_long mask1, mask2; /* * Create the do_pc1 table used * to affect pc1 permutation * when generating keys */ for(bit = 0; bit < 56; bit++) { comes_from_bit = pc1[bit] - 1; mask1 = bytemask[comes_from_bit % 8 + 1]; mask2 = longmask[bit % 28 + 4]; for(j = 0; j < 128; j++) { if(j & mask1) do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2; } } /* * Create the do_pc2 table used * to affect pc2 permutation when * generating keys */ for(bit = 0; bit < 48; bit++) { comes_from_bit = pc2[bit] - 1; mask1 = bytemask[comes_from_bit % 7 + 1]; mask2 = BITMASK(bit % 24); for(j = 0; j < 128; j++) { if(j & mask1) do_pc2[comes_from_bit / 7][j] |= mask2; } } /* * Now generate the table used to do combined * 32 bit permutation and e expansion * * We use it because we have to permute 16384 32 bit * longs into 48 bit in order to initialize sb. * * Looping 48 rounds per permutation becomes * just too slow... * */ clearmem((char*)eperm32tab, sizeof(eperm32tab)); for(bit = 0; bit < 48; bit++) { ufc_long inner_mask1,comes_from; comes_from = perm32[esel[bit]-1]-1; inner_mask1 = bytemask[comes_from % 8]; for(j = 256; j--;) { if(j & inner_mask1) eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24); } } /* * Create the sb tables: * * For each 12 bit segment of an 48 bit intermediate * result, the sb table precomputes the two 4 bit * values of the sbox lookups done with the two 6 * bit halves, shifts them to their proper place, * sends them through perm32 and finally E expands * them so that they are ready for the next * DES round. * */ for(sg = 0; sg < 4; sg++) { int j1, j2; int s1, s2; for(j1 = 0; j1 < 64; j1++) { s1 = s_lookup(2 * sg, j1); for(j2 = 0; j2 < 64; j2++) { ufc_long to_permute, inx; s2 = s_lookup(2 * sg + 1, j2); to_permute = ((s1 << 4) | s2) << (24 - 8 * sg); #ifdef _UFC_32_ inx = ((j1 << 6) | j2) << 1; sb[sg][inx ] = eperm32tab[0][(to_permute >> 24) & 0xff][0]; sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1]; sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0]; sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1]; sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0]; sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1]; sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0]; sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1]; #endif #ifdef _UFC_64_ inx = ((j1 << 6) | j2); sb[sg][inx] = ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) | (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1]; sb[sg][inx] |= ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) | (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1]; sb[sg][inx] |= ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) | (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1]; sb[sg][inx] |= ((long64)eperm32tab[3][(to_permute) & 0xff][0] << 32) | (long64)eperm32tab[3][(to_permute) & 0xff][1]; #endif } } } /* * Create an inverse matrix for esel telling * where to plug out bits if undoing it */ for(bit=48; bit--;) { e_inverse[esel[bit] - 1 ] = bit; e_inverse[esel[bit] - 1 + 32] = bit + 48; } /* * create efp: the matrix used to * undo the E expansion and effect final permutation */ clearmem((char*)efp, sizeof efp); for(bit = 0; bit < 64; bit++) { int o_bit, o_long; ufc_long word_value, inner_mask1, inner_mask2; int comes_from_f_bit, comes_from_e_bit; int comes_from_word, bit_within_word; /* See where bit i belongs in the two 32 bit long's */ o_long = bit / 32; /* 0..1 */ o_bit = bit % 32; /* 0..31 */ /* * And find a bit in the e permutated value setting this bit. * * Note: the e selection may have selected the same bit several * times. By the initialization of e_inverse, we only look * for one specific instance. */ comes_from_f_bit = final_perm[bit] - 1; /* 0..63 */ comes_from_e_bit = e_inverse[comes_from_f_bit]; /* 0..95 */ comes_from_word = comes_from_e_bit / 6; /* 0..15 */ bit_within_word = comes_from_e_bit % 6; /* 0..5 */ inner_mask1 = longmask[bit_within_word + 26]; inner_mask2 = longmask[o_bit]; for(word_value = 64; word_value--;) { if(word_value & inner_mask1) efp[comes_from_word][word_value][o_long] |= inner_mask2; } } initialized++; } /* * Process the elements of the sb table permuting the * bits swapped in the expansion by the current salt. */ #ifdef _UFC_32_ static void shuffle_sb(long32 *k, ufc_long saltbits) { ufc_long j; long32 x; for(j=4096; j--;) { x = (k[0] ^ k[1]) & (long32)saltbits; *k++ ^= x; *k++ ^= x; } } #endif #ifdef _UFC_64_ static void shuffle_sb(long64 *k, ufc_long saltbits) { ufc_long j; long64 x; for(j=4096; j--;) { x = ((*k >> 32) ^ *k) & (long64)saltbits; *k++ ^= (x << 32) | x; } } #endif /* * Setup the unit for a new salt * Hopefully we'll not see a new salt in each crypt call. */ static unsigned char current_salt[3] = "&&"; /* invalid value */ static ufc_long current_saltbits = 0; static int direction = 0; static void setup_salt(const char *s1) { ufc_long i, j, saltbits; const unsigned char *s2 = (const unsigned char *)s1; if(!initialized) ufc_init_des(); if(s2[0] == current_salt[0] && s2[1] == current_salt[1]) return; current_salt[0] = s2[0]; current_salt[1] = s2[1]; /* * This is the only crypt change to DES: * entries are swapped in the expansion table * according to the bits set in the salt. */ saltbits = 0; for(i = 0; i < 2; i++) { long c=ascii_to_bin(s2[i]); if(c < 0 || c > 63) c = 0; for(j = 0; j < 6; j++) { if((c >> j) & 0x1) saltbits |= BITMASK(6 * i + j); } } /* * Permute the sb table values * to reflect the changed e * selection table */ shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits); shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits); shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits); shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits); current_saltbits = saltbits; } static void ufc_mk_keytab(char *key) { ufc_long v1, v2, *k1; int i; #ifdef _UFC_32_ long32 v, *k2 = &_ufc_keytab[0][0]; #endif #ifdef _UFC_64_ long64 v, *k2 = &_ufc_keytab[0]; #endif v1 = v2 = 0; k1 = &do_pc1[0][0][0]; for(i = 8; i--;) { v1 |= k1[*key & 0x7f]; k1 += 128; v2 |= k1[*key++ & 0x7f]; k1 += 128; } for(i = 0; i < 16; i++) { k1 = &do_pc2[0][0]; v1 = (v1 << rots[i]) | (v1 >> (28 - rots[i])); v = k1[(v1 >> 21) & 0x7f]; k1 += 128; v |= k1[(v1 >> 14) & 0x7f]; k1 += 128; v |= k1[(v1 >> 7) & 0x7f]; k1 += 128; v |= k1[(v1 ) & 0x7f]; k1 += 128; #ifdef _UFC_32_ *k2++ = v; v = 0; #endif #ifdef _UFC_64_ v <<= 32; #endif v2 = (v2 << rots[i]) | (v2 >> (28 - rots[i])); v |= k1[(v2 >> 21) & 0x7f]; k1 += 128; v |= k1[(v2 >> 14) & 0x7f]; k1 += 128; v |= k1[(v2 >> 7) & 0x7f]; k1 += 128; v |= k1[(v2 ) & 0x7f]; *k2++ = v; } direction = 0; } /* * Undo an extra E selection and do final permutations */ ufc_long *_ufc_dofinalperm(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2) { ufc_long v1, v2, x; static ufc_long ary[2]; x = (l1 ^ l2) & current_saltbits; l1 ^= x; l2 ^= x; x = (r1 ^ r2) & current_saltbits; r1 ^= x; r2 ^= x; v1=v2=0; l1 >>= 3; l2 >>= 3; r1 >>= 3; r2 >>= 3; v1 |= efp[15][ r2 & 0x3f][0]; v2 |= efp[15][ r2 & 0x3f][1]; v1 |= efp[14][(r2 >>= 6) & 0x3f][0]; v2 |= efp[14][ r2 & 0x3f][1]; v1 |= efp[13][(r2 >>= 10) & 0x3f][0]; v2 |= efp[13][ r2 & 0x3f][1]; v1 |= efp[12][(r2 >>= 6) & 0x3f][0]; v2 |= efp[12][ r2 & 0x3f][1]; v1 |= efp[11][ r1 & 0x3f][0]; v2 |= efp[11][ r1 & 0x3f][1]; v1 |= efp[10][(r1 >>= 6) & 0x3f][0]; v2 |= efp[10][ r1 & 0x3f][1]; v1 |= efp[ 9][(r1 >>= 10) & 0x3f][0]; v2 |= efp[ 9][ r1 & 0x3f][1]; v1 |= efp[ 8][(r1 >>= 6) & 0x3f][0]; v2 |= efp[ 8][ r1 & 0x3f][1]; v1 |= efp[ 7][ l2 & 0x3f][0]; v2 |= efp[ 7][ l2 & 0x3f][1]; v1 |= efp[ 6][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 6][ l2 & 0x3f][1]; v1 |= efp[ 5][(l2 >>= 10) & 0x3f][0]; v2 |= efp[ 5][ l2 & 0x3f][1]; v1 |= efp[ 4][(l2 >>= 6) & 0x3f][0]; v2 |= efp[ 4][ l2 & 0x3f][1]; v1 |= efp[ 3][ l1 & 0x3f][0]; v2 |= efp[ 3][ l1 & 0x3f][1]; v1 |= efp[ 2][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 2][ l1 & 0x3f][1]; v1 |= efp[ 1][(l1 >>= 10) & 0x3f][0]; v2 |= efp[ 1][ l1 & 0x3f][1]; v1 |= efp[ 0][(l1 >>= 6) & 0x3f][0]; v2 |= efp[ 0][ l1 & 0x3f][1]; ary[0] = v1; ary[1] = v2; return ary; } /* * crypt only: convert from 64 bit to 11 bit ASCII * prefixing with the salt */ static char *output_conversion(ufc_long v1, ufc_long v2, const char *salt) { static char outbuf[14]; int i, s; outbuf[0] = salt[0]; outbuf[1] = salt[1] ? salt[1] : salt[0]; for(i = 0; i < 5; i++) outbuf[i + 2] = bin_to_ascii((v1 >> (26 - 6 * i)) & 0x3f); s = (v2 & 0xf) << 2; v2 = (v2 >> 2) | ((v1 & 0x3) << 30); for(i = 5; i < 10; i++) outbuf[i + 2] = bin_to_ascii((v2 >> (56 - 6 * i)) & 0x3f); outbuf[12] = bin_to_ascii(s); outbuf[13] = 0; return outbuf; } /* * UNIX crypt function */ static ufc_long *_ufc_doit(ufc_long , ufc_long, ufc_long, ufc_long, ufc_long); char *ufc_crypt(const char *key,const char *salt) { ufc_long *s; char ktab[9]; /* * Hack DES tables according to salt */ setup_salt(salt); /* * Setup key schedule */ clearmem(ktab, sizeof ktab); strncpy(ktab, key, 8); ufc_mk_keytab(ktab); /* * Go for the 25 DES encryptions */ s = _ufc_doit((ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)25); /* * And convert back to 6 bit ASCII */ return output_conversion(s[0], s[1], salt); } #ifdef _UFC_32_ /* * 32 bit version */ extern long32 _ufc_keytab[16][2]; extern long32 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[]; #define SBA(sb, v) (*(long32*)((char*)(sb)+(v))) static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr) { int i; long32 s, *k; while(itr--) { k = &_ufc_keytab[0][0]; for(i=8; i--; ) { s = *k++ ^ r1; l1 ^= SBA(_ufc_sb1, s & 0xffff); l2 ^= SBA(_ufc_sb1, (s & 0xffff)+4); l1 ^= SBA(_ufc_sb0, s >>= 16); l2 ^= SBA(_ufc_sb0, (s) +4); s = *k++ ^ r2; l1 ^= SBA(_ufc_sb3, s & 0xffff); l2 ^= SBA(_ufc_sb3, (s & 0xffff)+4); l1 ^= SBA(_ufc_sb2, s >>= 16); l2 ^= SBA(_ufc_sb2, (s) +4); s = *k++ ^ l1; r1 ^= SBA(_ufc_sb1, s & 0xffff); r2 ^= SBA(_ufc_sb1, (s & 0xffff)+4); r1 ^= SBA(_ufc_sb0, s >>= 16); r2 ^= SBA(_ufc_sb0, (s) +4); s = *k++ ^ l2; r1 ^= SBA(_ufc_sb3, s & 0xffff); r2 ^= SBA(_ufc_sb3, (s & 0xffff)+4); r1 ^= SBA(_ufc_sb2, s >>= 16); r2 ^= SBA(_ufc_sb2, (s) +4); } s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s; } return _ufc_dofinalperm(l1, l2, r1, r2); } #endif #ifdef _UFC_64_ /* * 64 bit version */ extern long64 _ufc_keytab[16]; extern long64 _ufc_sb0[], _ufc_sb1[], _ufc_sb2[], _ufc_sb3[]; #define SBA(sb, v) (*(long64*)((char*)(sb)+(v))) static ufc_long *_ufc_doit(ufc_long l1, ufc_long l2, ufc_long r1, ufc_long r2, ufc_long itr) { int i; long64 l, r, s, *k; l = (((long64)l1) << 32) | ((long64)l2); r = (((long64)r1) << 32) | ((long64)r2); while(itr--) { k = &_ufc_keytab[0]; for(i=8; i--; ) { s = *k++ ^ r; l ^= SBA(_ufc_sb3, (s >> 0) & 0xffff); l ^= SBA(_ufc_sb2, (s >> 16) & 0xffff); l ^= SBA(_ufc_sb1, (s >> 32) & 0xffff); l ^= SBA(_ufc_sb0, (s >> 48) & 0xffff); s = *k++ ^ l; r ^= SBA(_ufc_sb3, (s >> 0) & 0xffff); r ^= SBA(_ufc_sb2, (s >> 16) & 0xffff); r ^= SBA(_ufc_sb1, (s >> 32) & 0xffff); r ^= SBA(_ufc_sb0, (s >> 48) & 0xffff); } s=l; l=r; r=s; } l1 = l >> 32; l2 = l & 0xffffffff; r1 = r >> 32; r2 = r & 0xffffffff; return _ufc_dofinalperm(l1, l2, r1, r2); } #endif #else int ufc_dummy_procedure(void); int ufc_dummy_procedure(void) {return 0;} #endif ctdb-2.5.1.dfsg/lib/replace/configure0000755000175000017500000000065012245023514017316 0ustar mathieumathieu#!/bin/sh PREVPATH=`dirname $0` if [ -f $PREVPATH/../../buildtools/bin/waf ]; then WAF=../../buildtools/bin/waf elif [ -f $PREVPATH/buildtools/bin/waf ]; then WAF=./buildtools/bin/waf else echo "replace: Unable to find waf" exit 1 fi # using JOBS=1 gives maximum compatibility with # systems like AIX which have broken threading in python JOBS=1 export JOBS cd . || exit 1 $WAF configure "$@" || exit 1 cd $PREVPATH ctdb-2.5.1.dfsg/lib/replace/dlfcn.m40000644000175000017500000000136412245023514016742 0ustar mathieumathieudnl dummies provided by dlfcn.c if not available save_LIBS="$LIBS" LIBS="" libreplace_cv_dlfcn=no AC_SEARCH_LIBS(dlopen, dl) AC_CHECK_HEADERS(dlfcn.h) AC_CHECK_FUNCS([dlopen dlsym dlerror dlclose],[],[libreplace_cv_dlfcn=yes]) libreplace_cv_shl=no AC_SEARCH_LIBS(shl_load, sl) AC_CHECK_HEADERS(dl.h) AC_CHECK_FUNCS([shl_load shl_unload shl_findsym],[],[libreplace_cv_shl=yes]) AC_VERIFY_C_PROTOTYPE([void *dlopen(const char* filename, unsigned int flags)], [ return 0; ],[ AC_DEFINE(DLOPEN_TAKES_UNSIGNED_FLAGS, 1, [Whether dlopen takes unsigned int flags]) ],[],[ #include ]) if test x"${libreplace_cv_dlfcn}" = x"yes";then LIBREPLACEOBJ="${LIBREPLACEOBJ} $libreplacedir/dlfcn.o" fi LIBDL="$LIBS" AC_SUBST(LIBDL) LIBS="$save_LIBS" ctdb-2.5.1.dfsg/lib/replace/test/0000755000175000017500000000000012245023514016365 5ustar mathieumathieuctdb-2.5.1.dfsg/lib/replace/test/main.c0000644000175000017500000000205012245023514017452 0ustar mathieumathieu/* Unix SMB/CIFS implementation. libreplace tests Copyright (C) Jelmer Vernooij 2006 ** NOTE! The following LGPL license applies to the talloc ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include "replace.h" #include "replace-testsuite.h" int main(void) { bool ret = torture_local_replace(NULL); if (ret) return 0; return -1; } ctdb-2.5.1.dfsg/lib/replace/test/snprintf.c0000644000175000017500000000134512245023514020377 0ustar mathieumathieuvoid foo(const char *format, ...) { va_list ap; int len; char buf[20]; long long l = 1234567890; l *= 100; va_start(ap, format); len = vsnprintf(buf, 0, format, ap); va_end(ap); if (len != 5) exit(1); va_start(ap, format); len = vsnprintf(0, 0, format, ap); va_end(ap); if (len != 5) exit(2); if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(3); if (snprintf(buf, 20, "%lld", l) != 12 || strcmp(buf, "123456789000") != 0) exit(4); if (snprintf(buf, 20, "%zu", 123456789) != 9 || strcmp(buf, "123456789") != 0) exit(5); if (snprintf(buf, 20, "%2\$d %1\$d", 3, 4) != 3 || strcmp(buf, "4 3") != 0) exit(6); if (snprintf(buf, 20, "%s", 0) < 3) exit(7); printf("1"); exit(0); } main() { foo("hello"); } ctdb-2.5.1.dfsg/lib/replace/test/incoherent_mmap.c0000644000175000017500000000345612245023514021711 0ustar mathieumathieu/* In OpenBSD, if you write to a file, another process doesn't see it * in its mmap. Returns with exit status 0 if that is the case, 1 if * it's coherent, and other if there's a problem. */ #include #include #include #include #include #include #include #include #include #define DATA "coherent.mmap" int main(int argc, char *argv[]) { int tochild[2], toparent[2]; int fd; volatile unsigned char *map; unsigned char *page; const char *fname = argv[1]; char c = 0; if (pipe(tochild) != 0 || pipe(toparent) != 0) err(2, "Creating pipe"); if (!fname) fname = DATA; fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0600); if (fd < 0) err(2, "opening %s", fname); unlink(fname); switch (fork()) { case -1: err(2, "Fork"); case 0: close(tochild[1]); close(toparent[0]); /* Wait for parent to create file. */ if (read(tochild[0], &c, 1) != 1) err(2, "reading from parent"); /* Alter first byte. */ pwrite(fd, &c, 1, 0); if (write(toparent[1], &c, 1) != 1) err(2, "writing to parent"); exit(0); default: close(tochild[0]); close(toparent[1]); /* Create a file and mmap it. */ page = malloc(getpagesize()); memset(page, 0x42, getpagesize()); if (write(fd, page, getpagesize()) != getpagesize()) err(2, "writing first page"); map = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (map == MAP_FAILED) err(2, "mapping file"); if (*map != 0x42) errx(2, "first byte isn't 0x42!"); /* Tell child to alter file. */ if (write(tochild[1], &c, 1) != 1) err(2, "writing to child"); if (read(toparent[0], &c, 1) != 1) err(2, "reading from child"); if (*map) errx(0, "mmap incoherent: first byte isn't 0."); exit(1); } } ctdb-2.5.1.dfsg/lib/replace/test/testsuite.c0000644000175000017500000007057512245023514020600 0ustar mathieumathieu/* Unix SMB/CIFS implementation. libreplace tests Copyright (C) Jelmer Vernooij 2006 ** NOTE! The following LGPL license applies to the talloc ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include "replace.h" #include "replace-test.h" #include "replace-testsuite.h" /* we include all the system/ include files here so that libreplace tests them in the build farm */ #include "system/capability.h" #include "system/dir.h" #include "system/filesys.h" #include "system/glob.h" #include "system/iconv.h" #include "system/locale.h" #include "system/network.h" #include "system/passwd.h" #include "system/readline.h" #include "system/select.h" #include "system/shmem.h" #include "system/syslog.h" #include "system/terminal.h" #include "system/time.h" #include "system/wait.h" #include "system/aio.h" #define TESTFILE "testfile.dat" /* test ftruncate() function */ static int test_ftruncate(void) { struct stat st; int fd; const int size = 1234; printf("test: ftruncate\n"); unlink(TESTFILE); fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); if (fd == -1) { printf("failure: ftruncate [\n" "creating '%s' failed - %s\n]\n", TESTFILE, strerror(errno)); return false; } if (ftruncate(fd, size) != 0) { printf("failure: ftruncate [\n%s\n]\n", strerror(errno)); return false; } if (fstat(fd, &st) != 0) { printf("failure: ftruncate [\nfstat failed - %s\n]\n", strerror(errno)); return false; } if (st.st_size != size) { printf("failure: ftruncate [\ngave wrong size %d - expected %d\n]\n", (int)st.st_size, size); return false; } unlink(TESTFILE); printf("success: ftruncate\n"); return true; } /* test strlcpy() function. see http://www.gratisoft.us/todd/papers/strlcpy.html */ static int test_strlcpy(void) { char buf[4]; const struct { const char *src; size_t result; } tests[] = { { "abc", 3 }, { "abcdef", 6 }, { "abcd", 4 }, { "", 0 }, { NULL, 0 } }; int i; printf("test: strlcpy\n"); for (i=0;tests[i].src;i++) { if (strlcpy(buf, tests[i].src, sizeof(buf)) != tests[i].result) { printf("failure: strlcpy [\ntest %d failed\n]\n", i); return false; } } printf("success: strlcpy\n"); return true; } static int test_strlcat(void) { char tmp[10]; printf("test: strlcat\n"); strlcpy(tmp, "", sizeof(tmp)); if (strlcat(tmp, "bla", 3) != 3) { printf("failure: strlcat [\ninvalid return code\n]\n"); return false; } if (strcmp(tmp, "bl") != 0) { printf("failure: strlcat [\nexpected \"bl\", got \"%s\"\n]\n", tmp); return false; } strlcpy(tmp, "da", sizeof(tmp)); if (strlcat(tmp, "me", 4) != 4) { printf("failure: strlcat [\nexpected \"dam\", got \"%s\"\n]\n", tmp); return false; } printf("success: strlcat\n"); return true; } static int test_mktime(void) { /* FIXME */ return true; } static int test_initgroups(void) { /* FIXME */ return true; } static int test_memmove(void) { /* FIXME */ return true; } static int test_strdup(void) { char *x; printf("test: strdup\n"); x = strdup("bla"); if (strcmp("bla", x) != 0) { printf("failure: strdup [\nfailed: expected \"bla\", got \"%s\"\n]\n", x); return false; } free(x); printf("success: strdup\n"); return true; } static int test_setlinebuf(void) { printf("test: setlinebuf\n"); setlinebuf(stdout); printf("success: setlinebuf\n"); return true; } static int test_vsyslog(void) { /* FIXME */ return true; } static int test_timegm(void) { /* FIXME */ return true; } static int test_setenv(void) { #define TEST_SETENV(key, value, overwrite, result) do { \ int _ret; \ char *_v; \ _ret = setenv(key, value, overwrite); \ if (_ret != 0) { \ printf("failure: setenv [\n" \ "setenv(%s, %s, %d) failed\n" \ "]\n", \ key, value, overwrite); \ return false; \ } \ _v=getenv(key); \ if (!_v) { \ printf("failure: setenv [\n" \ "getenv(%s) returned NULL\n" \ "]\n", \ key); \ return false; \ } \ if (strcmp(result, _v) != 0) { \ printf("failure: setenv [\n" \ "getenv(%s): '%s' != '%s'\n" \ "]\n", \ key, result, _v); \ return false; \ } \ } while(0) #define TEST_UNSETENV(key) do { \ char *_v; \ unsetenv(key); \ _v=getenv(key); \ if (_v) { \ printf("failure: setenv [\n" \ "getenv(%s): NULL != '%s'\n" \ "]\n", \ SETENVTEST_KEY, _v); \ return false; \ } \ } while (0) #define SETENVTEST_KEY "SETENVTESTKEY" #define SETENVTEST_VAL "SETENVTESTVAL" printf("test: setenv\n"); TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"1", 0, SETENVTEST_VAL"1"); TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"2", 0, SETENVTEST_VAL"1"); TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"3", 1, SETENVTEST_VAL"3"); TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"4", 1, SETENVTEST_VAL"4"); TEST_UNSETENV(SETENVTEST_KEY); TEST_UNSETENV(SETENVTEST_KEY); TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"5", 0, SETENVTEST_VAL"5"); TEST_UNSETENV(SETENVTEST_KEY); TEST_UNSETENV(SETENVTEST_KEY); printf("success: setenv\n"); return true; } static int test_strndup(void) { char *x; printf("test: strndup\n"); x = strndup("bla", 0); if (strcmp(x, "") != 0) { printf("failure: strndup [\ninvalid\n]\n"); return false; } free(x); x = strndup("bla", 2); if (strcmp(x, "bl") != 0) { printf("failure: strndup [\ninvalid\n]\n"); return false; } free(x); x = strndup("bla", 10); if (strcmp(x, "bla") != 0) { printf("failure: strndup [\ninvalid\n]\n"); return false; } free(x); printf("success: strndup\n"); return true; } static int test_strnlen(void) { printf("test: strnlen\n"); if (strnlen("bla", 2) != 2) { printf("failure: strnlen [\nunexpected length\n]\n"); return false; } if (strnlen("some text\n", 0) != 0) { printf("failure: strnlen [\nunexpected length\n]\n"); return false; } if (strnlen("some text", 20) != 9) { printf("failure: strnlen [\nunexpected length\n]\n"); return false; } printf("success: strnlen\n"); return true; } static int test_waitpid(void) { /* FIXME */ return true; } static int test_seteuid(void) { /* FIXME */ return true; } static int test_setegid(void) { /* FIXME */ return true; } static int test_asprintf(void) { char *x; printf("test: asprintf\n"); if (asprintf(&x, "%d", 9) != 1) { printf("failure: asprintf [\ngenerate asprintf\n]\n"); return false; } if (strcmp(x, "9") != 0) { printf("failure: asprintf [\ngenerate asprintf\n]\n"); return false; } if (asprintf(&x, "dat%s", "a") != 4) { printf("failure: asprintf [\ngenerate asprintf\n]\n"); return false; } if (strcmp(x, "data") != 0) { printf("failure: asprintf [\ngenerate asprintf\n]\n"); return false; } printf("success: asprintf\n"); return true; } static int test_snprintf(void) { char tmp[10]; printf("test: snprintf\n"); if (snprintf(tmp, 3, "foo%d", 9) != 4) { printf("failure: snprintf [\nsnprintf return code failed\n]\n"); return false; } if (strcmp(tmp, "fo") != 0) { printf("failure: snprintf [\nsnprintf failed\n]\n"); return false; } printf("success: snprintf\n"); return true; } static int test_vasprintf(void) { /* FIXME */ return true; } static int test_vsnprintf(void) { /* FIXME */ return true; } static int test_opendir(void) { /* FIXME */ return true; } static int test_readdir(void) { printf("test: readdir\n"); if (test_readdir_os2_delete() != 0) { return false; } printf("success: readdir\n"); return true; } static int test_telldir(void) { /* FIXME */ return true; } static int test_seekdir(void) { /* FIXME */ return true; } static int test_dlopen(void) { /* FIXME: test dlopen, dlsym, dlclose, dlerror */ return true; } static int test_chroot(void) { /* FIXME: chroot() */ return true; } static int test_bzero(void) { /* FIXME: bzero */ return true; } static int test_strerror(void) { /* FIXME */ return true; } static int test_errno(void) { printf("test: errno\n"); errno = 3; if (errno != 3) { printf("failure: errno [\nerrno failed\n]\n"); return false; } printf("success: errno\n"); return true; } static int test_mkdtemp(void) { /* FIXME */ return true; } static int test_mkstemp(void) { /* FIXME */ return true; } static int test_pread(void) { /* FIXME */ return true; } static int test_pwrite(void) { /* FIXME */ return true; } static int test_inet_ntoa(void) { /* FIXME */ return true; } #define TEST_STRTO_X(type,fmt,func,str,base,res,diff,rrnoo) do {\ type _v; \ char _s[64]; \ char *_p = NULL;\ char *_ep = NULL; \ strlcpy(_s, str, sizeof(_s));\ if (diff >= 0) { \ _ep = &_s[diff]; \ } \ errno = 0; \ _v = func(_s, &_p, base); \ if (errno != rrnoo) { \ printf("failure: %s [\n" \ "\t%s\n" \ "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \ "\terrno: %d != %d\n" \ "]\n", \ __STRING(func), __location__, __STRING(func), \ str, diff, base, res, _v, rrnoo, errno); \ return false; \ } else if (_v != res) { \ printf("failure: %s [\n" \ "\t%s\n" \ "\t%s(\"%s\",%d,%d): " fmt " != " fmt "\n" \ "]\n", \ __STRING(func), __location__, __STRING(func), \ str, diff, base, res, _v); \ return false; \ } else if (_p != _ep) { \ printf("failure: %s [\n" \ "\t%s\n" \ "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \ "\tptr: %p - %p = %d != %d\n" \ "]\n", \ __STRING(func), __location__, __STRING(func), \ str, diff, base, res, _v, _ep, _p, (int)(diff - (_ep - _p)), diff); \ return false; \ } \ } while (0) static int test_strtoll(void) { printf("test: strtoll\n"); #define TEST_STRTOLL(str,base,res,diff,errnoo) TEST_STRTO_X(long long int, "%lld", strtoll,str,base,res,diff,errnoo) TEST_STRTOLL("15", 10, 15LL, 2, 0); TEST_STRTOLL(" 15", 10, 15LL, 4, 0); TEST_STRTOLL("15", 0, 15LL, 2, 0); TEST_STRTOLL(" 15 ", 0, 15LL, 3, 0); TEST_STRTOLL("+15", 10, 15LL, 3, 0); TEST_STRTOLL(" +15", 10, 15LL, 5, 0); TEST_STRTOLL("+15", 0, 15LL, 3, 0); TEST_STRTOLL(" +15 ", 0, 15LL, 4, 0); TEST_STRTOLL("-15", 10, -15LL, 3, 0); TEST_STRTOLL(" -15", 10, -15LL, 5, 0); TEST_STRTOLL("-15", 0, -15LL, 3, 0); TEST_STRTOLL(" -15 ", 0, -15LL, 4, 0); TEST_STRTOLL("015", 10, 15LL, 3, 0); TEST_STRTOLL(" 015", 10, 15LL, 5, 0); TEST_STRTOLL("015", 0, 13LL, 3, 0); TEST_STRTOLL(" 015", 0, 13LL, 5, 0); TEST_STRTOLL("0x15", 10, 0LL, 1, 0); TEST_STRTOLL(" 0x15", 10, 0LL, 3, 0); TEST_STRTOLL("0x15", 0, 21LL, 4, 0); TEST_STRTOLL(" 0x15", 0, 21LL, 6, 0); TEST_STRTOLL("10", 16, 16LL, 2, 0); TEST_STRTOLL(" 10 ", 16, 16LL, 4, 0); TEST_STRTOLL("0x10", 16, 16LL, 4, 0); TEST_STRTOLL("0x10", 0, 16LL, 4, 0); TEST_STRTOLL(" 0x10 ", 0, 16LL, 5, 0); TEST_STRTOLL("+10", 16, 16LL, 3, 0); TEST_STRTOLL(" +10 ", 16, 16LL, 5, 0); TEST_STRTOLL("+0x10", 16, 16LL, 5, 0); TEST_STRTOLL("+0x10", 0, 16LL, 5, 0); TEST_STRTOLL(" +0x10 ", 0, 16LL, 6, 0); TEST_STRTOLL("-10", 16, -16LL, 3, 0); TEST_STRTOLL(" -10 ", 16, -16LL, 5, 0); TEST_STRTOLL("-0x10", 16, -16LL, 5, 0); TEST_STRTOLL("-0x10", 0, -16LL, 5, 0); TEST_STRTOLL(" -0x10 ", 0, -16LL, 6, 0); TEST_STRTOLL("010", 16, 16LL, 3, 0); TEST_STRTOLL(" 010 ", 16, 16LL, 5, 0); TEST_STRTOLL("-010", 16, -16LL, 4, 0); TEST_STRTOLL("11", 8, 9LL, 2, 0); TEST_STRTOLL("011", 8, 9LL, 3, 0); TEST_STRTOLL("011", 0, 9LL, 3, 0); TEST_STRTOLL("-11", 8, -9LL, 3, 0); TEST_STRTOLL("-011", 8, -9LL, 4, 0); TEST_STRTOLL("-011", 0, -9LL, 4, 0); TEST_STRTOLL("011", 8, 9LL, 3, 0); TEST_STRTOLL("011", 0, 9LL, 3, 0); TEST_STRTOLL("-11", 8, -9LL, 3, 0); TEST_STRTOLL("-011", 8, -9LL, 4, 0); TEST_STRTOLL("-011", 0, -9LL, 4, 0); TEST_STRTOLL("Text", 0, 0LL, 0, 0); TEST_STRTOLL("9223372036854775807", 10, 9223372036854775807LL, 19, 0); TEST_STRTOLL("9223372036854775807", 0, 9223372036854775807LL, 19, 0); TEST_STRTOLL("9223372036854775808", 0, 9223372036854775807LL, 19, ERANGE); TEST_STRTOLL("9223372036854775808", 10, 9223372036854775807LL, 19, ERANGE); TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LL, 18, 0); TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 18, 0); TEST_STRTOLL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 16, 0); TEST_STRTOLL("0x8000000000000000", 0, 9223372036854775807LL, 18, ERANGE); TEST_STRTOLL("0x8000000000000000", 16, 9223372036854775807LL, 18, ERANGE); TEST_STRTOLL("80000000000000000", 16, 9223372036854775807LL, 17, ERANGE); TEST_STRTOLL("0777777777777777777777", 0, 9223372036854775807LL, 22, 0); TEST_STRTOLL("0777777777777777777777", 8, 9223372036854775807LL, 22, 0); TEST_STRTOLL("777777777777777777777", 8, 9223372036854775807LL, 21, 0); TEST_STRTOLL("01000000000000000000000", 0, 9223372036854775807LL, 23, ERANGE); TEST_STRTOLL("01000000000000000000000", 8, 9223372036854775807LL, 23, ERANGE); TEST_STRTOLL("1000000000000000000000", 8, 9223372036854775807LL, 22, ERANGE); TEST_STRTOLL("-9223372036854775808", 10, -9223372036854775807LL -1, 20, 0); TEST_STRTOLL("-9223372036854775808", 0, -9223372036854775807LL -1, 20, 0); TEST_STRTOLL("-9223372036854775809", 0, -9223372036854775807LL -1, 20, ERANGE); TEST_STRTOLL("-9223372036854775809", 10, -9223372036854775807LL -1, 20, ERANGE); TEST_STRTOLL("-0x8000000000000000", 0, -9223372036854775807LL -1, 19, 0); TEST_STRTOLL("-0x8000000000000000", 16, -9223372036854775807LL -1, 19, 0); TEST_STRTOLL("-8000000000000000", 16, -9223372036854775807LL -1, 17, 0); TEST_STRTOLL("-0x8000000000000001", 0, -9223372036854775807LL -1, 19, ERANGE); TEST_STRTOLL("-0x8000000000000001", 16, -9223372036854775807LL -1, 19, ERANGE); TEST_STRTOLL("-80000000000000001", 16, -9223372036854775807LL -1, 18, ERANGE); TEST_STRTOLL("-01000000000000000000000",0, -9223372036854775807LL -1, 24, 0); TEST_STRTOLL("-01000000000000000000000",8, -9223372036854775807LL -1, 24, 0); TEST_STRTOLL("-1000000000000000000000", 8, -9223372036854775807LL -1, 23, 0); TEST_STRTOLL("-01000000000000000000001",0, -9223372036854775807LL -1, 24, ERANGE); TEST_STRTOLL("-01000000000000000000001",8, -9223372036854775807LL -1, 24, ERANGE); TEST_STRTOLL("-1000000000000000000001", 8, -9223372036854775807LL -1, 23, ERANGE); printf("success: strtoll\n"); return true; } static int test_strtoull(void) { printf("test: strtoull\n"); #define TEST_STRTOULL(str,base,res,diff,errnoo) TEST_STRTO_X(long long unsigned int,"%llu",strtoull,str,base,res,diff,errnoo) TEST_STRTOULL("15", 10, 15LLU, 2, 0); TEST_STRTOULL(" 15", 10, 15LLU, 4, 0); TEST_STRTOULL("15", 0, 15LLU, 2, 0); TEST_STRTOULL(" 15 ", 0, 15LLU, 3, 0); TEST_STRTOULL("+15", 10, 15LLU, 3, 0); TEST_STRTOULL(" +15", 10, 15LLU, 5, 0); TEST_STRTOULL("+15", 0, 15LLU, 3, 0); TEST_STRTOULL(" +15 ", 0, 15LLU, 4, 0); TEST_STRTOULL("-15", 10, 18446744073709551601LLU, 3, 0); TEST_STRTOULL(" -15", 10, 18446744073709551601LLU, 5, 0); TEST_STRTOULL("-15", 0, 18446744073709551601LLU, 3, 0); TEST_STRTOULL(" -15 ", 0, 18446744073709551601LLU, 4, 0); TEST_STRTOULL("015", 10, 15LLU, 3, 0); TEST_STRTOULL(" 015", 10, 15LLU, 5, 0); TEST_STRTOULL("015", 0, 13LLU, 3, 0); TEST_STRTOULL(" 015", 0, 13LLU, 5, 0); TEST_STRTOULL("0x15", 10, 0LLU, 1, 0); TEST_STRTOULL(" 0x15", 10, 0LLU, 3, 0); TEST_STRTOULL("0x15", 0, 21LLU, 4, 0); TEST_STRTOULL(" 0x15", 0, 21LLU, 6, 0); TEST_STRTOULL("10", 16, 16LLU, 2, 0); TEST_STRTOULL(" 10 ", 16, 16LLU, 4, 0); TEST_STRTOULL("0x10", 16, 16LLU, 4, 0); TEST_STRTOULL("0x10", 0, 16LLU, 4, 0); TEST_STRTOULL(" 0x10 ", 0, 16LLU, 5, 0); TEST_STRTOULL("+10", 16, 16LLU, 3, 0); TEST_STRTOULL(" +10 ", 16, 16LLU, 5, 0); TEST_STRTOULL("+0x10", 16, 16LLU, 5, 0); TEST_STRTOULL("+0x10", 0, 16LLU, 5, 0); TEST_STRTOULL(" +0x10 ", 0, 16LLU, 6, 0); TEST_STRTOULL("-10", 16, -16LLU, 3, 0); TEST_STRTOULL(" -10 ", 16, -16LLU, 5, 0); TEST_STRTOULL("-0x10", 16, -16LLU, 5, 0); TEST_STRTOULL("-0x10", 0, -16LLU, 5, 0); TEST_STRTOULL(" -0x10 ", 0, -16LLU, 6, 0); TEST_STRTOULL("010", 16, 16LLU, 3, 0); TEST_STRTOULL(" 010 ", 16, 16LLU, 5, 0); TEST_STRTOULL("-010", 16, -16LLU, 4, 0); TEST_STRTOULL("11", 8, 9LLU, 2, 0); TEST_STRTOULL("011", 8, 9LLU, 3, 0); TEST_STRTOULL("011", 0, 9LLU, 3, 0); TEST_STRTOULL("-11", 8, -9LLU, 3, 0); TEST_STRTOULL("-011", 8, -9LLU, 4, 0); TEST_STRTOULL("-011", 0, -9LLU, 4, 0); TEST_STRTOULL("011", 8, 9LLU, 3, 0); TEST_STRTOULL("011", 0, 9LLU, 3, 0); TEST_STRTOULL("-11", 8, -9LLU, 3, 0); TEST_STRTOULL("-011", 8, -9LLU, 4, 0); TEST_STRTOULL("-011", 0, -9LLU, 4, 0); TEST_STRTOULL("Text", 0, 0LLU, 0, 0); TEST_STRTOULL("9223372036854775807", 10, 9223372036854775807LLU, 19, 0); TEST_STRTOULL("9223372036854775807", 0, 9223372036854775807LLU, 19, 0); TEST_STRTOULL("9223372036854775808", 0, 9223372036854775808LLU, 19, 0); TEST_STRTOULL("9223372036854775808", 10, 9223372036854775808LLU, 19, 0); TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LLU, 18, 0); TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 18, 0); TEST_STRTOULL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 16, 0); TEST_STRTOULL("0x8000000000000000", 0, 9223372036854775808LLU, 18, 0); TEST_STRTOULL("0x8000000000000000", 16, 9223372036854775808LLU, 18, 0); TEST_STRTOULL("8000000000000000", 16, 9223372036854775808LLU, 16, 0); TEST_STRTOULL("0777777777777777777777", 0, 9223372036854775807LLU, 22, 0); TEST_STRTOULL("0777777777777777777777", 8, 9223372036854775807LLU, 22, 0); TEST_STRTOULL("777777777777777777777", 8, 9223372036854775807LLU, 21, 0); TEST_STRTOULL("01000000000000000000000",0, 9223372036854775808LLU, 23, 0); TEST_STRTOULL("01000000000000000000000",8, 9223372036854775808LLU, 23, 0); TEST_STRTOULL("1000000000000000000000", 8, 9223372036854775808LLU, 22, 0); TEST_STRTOULL("-9223372036854775808", 10, 9223372036854775808LLU, 20, 0); TEST_STRTOULL("-9223372036854775808", 0, 9223372036854775808LLU, 20, 0); TEST_STRTOULL("-9223372036854775809", 0, 9223372036854775807LLU, 20, 0); TEST_STRTOULL("-9223372036854775809", 10, 9223372036854775807LLU, 20, 0); TEST_STRTOULL("-0x8000000000000000", 0, 9223372036854775808LLU, 19, 0); TEST_STRTOULL("-0x8000000000000000", 16, 9223372036854775808LLU, 19, 0); TEST_STRTOULL("-8000000000000000", 16, 9223372036854775808LLU, 17, 0); TEST_STRTOULL("-0x8000000000000001", 0, 9223372036854775807LLU, 19, 0); TEST_STRTOULL("-0x8000000000000001", 16, 9223372036854775807LLU, 19, 0); TEST_STRTOULL("-8000000000000001", 16, 9223372036854775807LLU, 17, 0); TEST_STRTOULL("-01000000000000000000000",0, 9223372036854775808LLU, 24, 0); TEST_STRTOULL("-01000000000000000000000",8, 9223372036854775808LLU, 24, 0); TEST_STRTOULL("-1000000000000000000000",8, 9223372036854775808LLU, 23, 0); TEST_STRTOULL("-01000000000000000000001",0, 9223372036854775807LLU, 24, 0); TEST_STRTOULL("-01000000000000000000001",8, 9223372036854775807LLU, 24, 0); TEST_STRTOULL("-1000000000000000000001",8, 9223372036854775807LLU, 23, 0); TEST_STRTOULL("18446744073709551615", 0, 18446744073709551615LLU, 20, 0); TEST_STRTOULL("18446744073709551615", 10, 18446744073709551615LLU, 20, 0); TEST_STRTOULL("18446744073709551616", 0, 18446744073709551615LLU, 20, ERANGE); TEST_STRTOULL("18446744073709551616", 10, 18446744073709551615LLU, 20, ERANGE); TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 0, 18446744073709551615LLU, 18, 0); TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 18, 0); TEST_STRTOULL("FFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 16, 0); TEST_STRTOULL("0x10000000000000000", 0, 18446744073709551615LLU, 19, ERANGE); TEST_STRTOULL("0x10000000000000000", 16, 18446744073709551615LLU, 19, ERANGE); TEST_STRTOULL("10000000000000000", 16, 18446744073709551615LLU, 17, ERANGE); TEST_STRTOULL("01777777777777777777777",0, 18446744073709551615LLU, 23, 0); TEST_STRTOULL("01777777777777777777777",8, 18446744073709551615LLU, 23, 0); TEST_STRTOULL("1777777777777777777777", 8, 18446744073709551615LLU, 22, 0); TEST_STRTOULL("02000000000000000000000",0, 18446744073709551615LLU, 23, ERANGE); TEST_STRTOULL("02000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE); TEST_STRTOULL("2000000000000000000000", 8, 18446744073709551615LLU, 22, ERANGE); TEST_STRTOULL("-18446744073709551615", 0, 1LLU, 21, 0); TEST_STRTOULL("-18446744073709551615", 10, 1LLU, 21, 0); TEST_STRTOULL("-18446744073709551616", 0, 18446744073709551615LLU, 21, ERANGE); TEST_STRTOULL("-18446744073709551616", 10, 18446744073709551615LLU, 21, ERANGE); TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 0, 1LLU, 19, 0); TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 16, 1LLU, 19, 0); TEST_STRTOULL("-FFFFFFFFFFFFFFFF", 16, 1LLU, 17, 0); TEST_STRTOULL("-0x10000000000000000", 0, 18446744073709551615LLU, 20, ERANGE); TEST_STRTOULL("-0x10000000000000000", 16, 18446744073709551615LLU, 20, ERANGE); TEST_STRTOULL("-10000000000000000", 16, 18446744073709551615LLU, 18, ERANGE); TEST_STRTOULL("-01777777777777777777777",0, 1LLU, 24, 0); TEST_STRTOULL("-01777777777777777777777",8, 1LLU, 24, 0); TEST_STRTOULL("-1777777777777777777777",8, 1LLU, 23, 0); TEST_STRTOULL("-02000000000000000000000",0, 18446744073709551615LLU, 24, ERANGE); TEST_STRTOULL("-02000000000000000000000",8, 18446744073709551615LLU, 24, ERANGE); TEST_STRTOULL("-2000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE); printf("success: strtoull\n"); return true; } /* FIXME: Types: bool socklen_t uint{8,16,32,64}_t int{8,16,32,64}_t intptr_t Constants: PATH_NAME_MAX UINT{16,32,64}_MAX INT32_MAX */ static int test_va_copy(void) { /* FIXME */ return true; } static int test_FUNCTION(void) { printf("test: FUNCTION\n"); if (strcmp(__FUNCTION__, "test_FUNCTION") != 0) { printf("failure: FUNCTION [\nFUNCTION invalid\n]\n"); return false; } printf("success: FUNCTION\n"); return true; } static int test_MIN(void) { printf("test: MIN\n"); if (MIN(20, 1) != 1) { printf("failure: MIN [\nMIN invalid\n]\n"); return false; } if (MIN(1, 20) != 1) { printf("failure: MIN [\nMIN invalid\n]\n"); return false; } printf("success: MIN\n"); return true; } static int test_MAX(void) { printf("test: MAX\n"); if (MAX(20, 1) != 20) { printf("failure: MAX [\nMAX invalid\n]\n"); return false; } if (MAX(1, 20) != 20) { printf("failure: MAX [\nMAX invalid\n]\n"); return false; } printf("success: MAX\n"); return true; } static int test_socketpair(void) { int sock[2]; char buf[20]; printf("test: socketpair\n"); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == -1) { printf("failure: socketpair [\n" "socketpair() failed\n" "]\n"); return false; } if (write(sock[1], "automatisch", 12) == -1) { printf("failure: socketpair [\n" "write() failed: %s\n" "]\n", strerror(errno)); return false; } if (read(sock[0], buf, 12) == -1) { printf("failure: socketpair [\n" "read() failed: %s\n" "]\n", strerror(errno)); return false; } if (strcmp(buf, "automatisch") != 0) { printf("failure: socketpair [\n" "expected: automatisch, got: %s\n" "]\n", buf); return false; } printf("success: socketpair\n"); return true; } extern int libreplace_test_strptime(void); static int test_strptime(void) { return libreplace_test_strptime(); } extern int getifaddrs_test(void); static int test_getifaddrs(void) { printf("test: getifaddrs\n"); if (getifaddrs_test() != 0) { printf("failure: getifaddrs\n"); return false; } printf("success: getifaddrs\n"); return true; } static int test_utime(void) { struct utimbuf u; struct stat st1, st2, st3; int fd; printf("test: utime\n"); unlink(TESTFILE); fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); if (fd == -1) { printf("failure: utime [\n" "creating '%s' failed - %s\n]\n", TESTFILE, strerror(errno)); return false; } if (fstat(fd, &st1) != 0) { printf("failure: utime [\n" "fstat (1) failed - %s\n]\n", strerror(errno)); return false; } u.actime = st1.st_atime + 300; u.modtime = st1.st_mtime - 300; if (utime(TESTFILE, &u) != 0) { printf("failure: utime [\n" "utime(&u) failed - %s\n]\n", strerror(errno)); return false; } if (fstat(fd, &st2) != 0) { printf("failure: utime [\n" "fstat (2) failed - %s\n]\n", strerror(errno)); return false; } if (utime(TESTFILE, NULL) != 0) { printf("failure: utime [\n" "utime(NULL) failed - %s\n]\n", strerror(errno)); return false; } if (fstat(fd, &st3) != 0) { printf("failure: utime [\n" "fstat (3) failed - %s\n]\n", strerror(errno)); return false; } #define CMP_VAL(a,c,b) do { \ if (a c b) { \ printf("failure: utime [\n" \ "%s: %s(%d) %s %s(%d)\n]\n", \ __location__, \ #a, (int)a, #c, #b, (int)b); \ return false; \ } \ } while(0) #define EQUAL_VAL(a,b) CMP_VAL(a,!=,b) #define GREATER_VAL(a,b) CMP_VAL(a,<=,b) #define LESSER_VAL(a,b) CMP_VAL(a,>=,b) EQUAL_VAL(st2.st_atime, st1.st_atime + 300); EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300); LESSER_VAL(st3.st_atime, st2.st_atime); GREATER_VAL(st3.st_mtime, st2.st_mtime); #undef CMP_VAL #undef EQUAL_VAL #undef GREATER_VAL #undef LESSER_VAL unlink(TESTFILE); printf("success: utime\n"); return true; } static int test_utimes(void) { struct timeval tv[2]; struct stat st1, st2; int fd; printf("test: utimes\n"); unlink(TESTFILE); fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); if (fd == -1) { printf("failure: utimes [\n" "creating '%s' failed - %s\n]\n", TESTFILE, strerror(errno)); return false; } if (fstat(fd, &st1) != 0) { printf("failure: utimes [\n" "fstat (1) failed - %s\n]\n", strerror(errno)); return false; } ZERO_STRUCT(tv); tv[0].tv_sec = st1.st_atime + 300; tv[1].tv_sec = st1.st_mtime - 300; if (utimes(TESTFILE, tv) != 0) { printf("failure: utimes [\n" "utimes(tv) failed - %s\n]\n", strerror(errno)); return false; } if (fstat(fd, &st2) != 0) { printf("failure: utimes [\n" "fstat (2) failed - %s\n]\n", strerror(errno)); return false; } #define EQUAL_VAL(a,b) do { \ if (a != b) { \ printf("failure: utimes [\n" \ "%s: %s(%d) != %s(%d)\n]\n", \ __location__, \ #a, (int)a, #b, (int)b); \ return false; \ } \ } while(0) EQUAL_VAL(st2.st_atime, st1.st_atime + 300); EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300); #undef EQUAL_VAL unlink(TESTFILE); printf("success: utimes\n"); return true; } static int test_memmem(void) { char *s; printf("test: memmem\n"); s = (char *)memmem("foo", 3, "fo", 2); if (strcmp(s, "foo") != 0) { printf(__location__ ": Failed memmem\n"); return false; } s = (char *)memmem("foo", 3, "", 0); /* it is allowable for this to return NULL (as happens on FreeBSD) */ if (s && strcmp(s, "foo") != 0) { printf(__location__ ": Failed memmem\n"); return false; } s = (char *)memmem("foo", 4, "o", 1); if (strcmp(s, "oo") != 0) { printf(__location__ ": Failed memmem\n"); return false; } s = (char *)memmem("foobarfodx", 11, "fod", 3); if (strcmp(s, "fodx") != 0) { printf(__location__ ": Failed memmem\n"); return false; } printf("success: memmem\n"); return true; } bool torture_local_replace(struct torture_context *ctx) { bool ret = true; ret &= test_ftruncate(); ret &= test_strlcpy(); ret &= test_strlcat(); ret &= test_mktime(); ret &= test_initgroups(); ret &= test_memmove(); ret &= test_strdup(); ret &= test_setlinebuf(); ret &= test_vsyslog(); ret &= test_timegm(); ret &= test_setenv(); ret &= test_strndup(); ret &= test_strnlen(); ret &= test_waitpid(); ret &= test_seteuid(); ret &= test_setegid(); ret &= test_asprintf(); ret &= test_snprintf(); ret &= test_vasprintf(); ret &= test_vsnprintf(); ret &= test_opendir(); ret &= test_readdir(); ret &= test_telldir(); ret &= test_seekdir(); ret &= test_dlopen(); ret &= test_chroot(); ret &= test_bzero(); ret &= test_strerror(); ret &= test_errno(); ret &= test_mkdtemp(); ret &= test_mkstemp(); ret &= test_pread(); ret &= test_pwrite(); ret &= test_inet_ntoa(); ret &= test_strtoll(); ret &= test_strtoull(); ret &= test_va_copy(); ret &= test_FUNCTION(); ret &= test_MIN(); ret &= test_MAX(); ret &= test_socketpair(); ret &= test_strptime(); ret &= test_getifaddrs(); ret &= test_utime(); ret &= test_utimes(); ret &= test_memmem(); return ret; } ctdb-2.5.1.dfsg/lib/replace/test/strptime.c0000644000175000017500000000660612245023514020410 0ustar mathieumathieu #ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME #include #include #include #define true 1 #define false 0 #ifndef __STRING #define __STRING(x) #x #endif /* make printf a no-op */ #define printf if(0) printf #else /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */ #include "replace.h" #include "system/time.h" #include "replace-test.h" #endif /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */ int libreplace_test_strptime(void) { const char *s = "20070414101546Z"; char *ret; struct tm t, t2; memset(&t, 0, sizeof(t)); memset(&t2, 0, sizeof(t2)); printf("test: strptime\n"); ret = strptime(s, "%Y%m%d%H%M%S", &t); if ( ret == NULL ) { printf("failure: strptime [\n" "returned NULL\n" "]\n"); return false; } if ( *ret != 'Z' ) { printf("failure: strptime [\n" "ret doesn't point to 'Z'\n" "]\n"); return false; } ret = strptime(s, "%Y%m%d%H%M%SZ", &t2); if ( ret == NULL ) { printf("failure: strptime [\n" "returned NULL with Z\n" "]\n"); return false; } if ( *ret != '\0' ) { printf("failure: strptime [\n" "ret doesn't point to '\\0'\n" "]\n"); return false; } #define CMP_TM_ELEMENT(t1,t2,elem) \ if (t1.elem != t2.elem) { \ printf("failure: strptime [\n" \ "result differs if the format string has a 'Z' at the end\n" \ "element: %s %d != %d\n" \ "]\n", \ __STRING(elen), t1.elem, t2.elem); \ return false; \ } CMP_TM_ELEMENT(t,t2,tm_sec); CMP_TM_ELEMENT(t,t2,tm_min); CMP_TM_ELEMENT(t,t2,tm_hour); CMP_TM_ELEMENT(t,t2,tm_mday); CMP_TM_ELEMENT(t,t2,tm_mon); CMP_TM_ELEMENT(t,t2,tm_year); CMP_TM_ELEMENT(t,t2,tm_wday); CMP_TM_ELEMENT(t,t2,tm_yday); CMP_TM_ELEMENT(t,t2,tm_isdst); if (t.tm_sec != 46) { printf("failure: strptime [\n" "tm_sec: expected: 46, got: %d\n" "]\n", t.tm_sec); return false; } if (t.tm_min != 15) { printf("failure: strptime [\n" "tm_min: expected: 15, got: %d\n" "]\n", t.tm_min); return false; } if (t.tm_hour != 10) { printf("failure: strptime [\n" "tm_hour: expected: 10, got: %d\n" "]\n", t.tm_hour); return false; } if (t.tm_mday != 14) { printf("failure: strptime [\n" "tm_mday: expected: 14, got: %d\n" "]\n", t.tm_mday); return false; } if (t.tm_mon != 3) { printf("failure: strptime [\n" "tm_mon: expected: 3, got: %d\n" "]\n", t.tm_mon); return false; } if (t.tm_year != 107) { printf("failure: strptime [\n" "tm_year: expected: 107, got: %d\n" "]\n", t.tm_year); return false; } if (t.tm_wday != 6) { /* saturday */ printf("failure: strptime [\n" "tm_wday: expected: 6, got: %d\n" "]\n", t.tm_wday); return false; } if (t.tm_yday != 103) { printf("failure: strptime [\n" "tm_yday: expected: 103, got: %d\n" "]\n", t.tm_yday); return false; } /* we don't test this as it depends on the host configuration if (t.tm_isdst != 0) { printf("failure: strptime [\n" "tm_isdst: expected: 0, got: %d\n" "]\n", t.tm_isdst); return false; }*/ printf("success: strptime\n"); return true; } #ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME int main (void) { int ret; ret = libreplace_test_strptime(); if (ret == false) return 1; return 0; } #endif ctdb-2.5.1.dfsg/lib/replace/test/shared_mremap.c0000644000175000017500000000132712245023514021343 0ustar mathieumathieu/* this tests whether we can use mremap */ #if defined(HAVE_UNISTD_H) #include #endif #include #include #include #include #define DATA "conftest.mmap" #ifndef MAP_FILE #define MAP_FILE 0 #endif #ifndef MAP_FAILED #define MAP_FAILED (int *)-1 #endif main() { int *buf; int fd; int err = 1; fd = open(DATA, O_RDWR|O_CREAT|O_TRUNC, 0666); if (fd == -1) { exit(1); } buf = (int *)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { goto done; } buf = mremap(buf, 0x1000, 0x2000, MREMAP_MAYMOVE); if (buf == MAP_FAILED) { goto done; } err = 0; done: close(fd); unlink(DATA); exit(err); } ctdb-2.5.1.dfsg/lib/replace/test/getifaddrs.c0000644000175000017500000000457512245023514020660 0ustar mathieumathieu/* * Unix SMB/CIFS implementation. * * libreplace getifaddrs test * * Copyright (C) Michael Adam 2008 * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . */ #ifndef AUTOCONF_TEST #include "replace.h" #include "system/network.h" #include "replace-test.h" #endif #ifdef HAVE_INET_NTOP #define rep_inet_ntop inet_ntop #endif static const char *format_sockaddr(struct sockaddr *addr, char *addrstring, socklen_t addrlen) { const char *result = NULL; if (addr->sa_family == AF_INET) { result = rep_inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, addrstring, addrlen); #ifdef HAVE_STRUCT_SOCKADDR_IN6 } else if (addr->sa_family == AF_INET6) { result = rep_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, addrstring, addrlen); #endif } return result; } int getifaddrs_test(void) { struct ifaddrs *ifs = NULL; struct ifaddrs *ifs_head = NULL; int ret; ret = getifaddrs(&ifs); ifs_head = ifs; if (ret != 0) { fprintf(stderr, "getifaddrs() failed: %s\n", strerror(errno)); return 1; } while (ifs) { printf("%-10s ", ifs->ifa_name); if (ifs->ifa_addr != NULL) { char addrstring[INET6_ADDRSTRLEN]; const char *result; result = format_sockaddr(ifs->ifa_addr, addrstring, sizeof(addrstring)); if (result != NULL) { printf("IP=%s ", addrstring); } if (ifs->ifa_netmask != NULL) { result = format_sockaddr(ifs->ifa_netmask, addrstring, sizeof(addrstring)); if (result != NULL) { printf("NETMASK=%s", addrstring); } } else { printf("AF=%d ", ifs->ifa_addr->sa_family); } } else { printf(""); } printf("\n"); ifs = ifs->ifa_next; } freeifaddrs(ifs_head); return 0; } ctdb-2.5.1.dfsg/lib/replace/test/os2_delete.c0000644000175000017500000000504712245023514020564 0ustar mathieumathieu/* test readdir/unlink pattern that OS/2 uses tridge@samba.org July 2005 */ #include #include #include #include #include #include #include #include #include #include "replace-test.h" #define NUM_FILES 700 #define READDIR_SIZE 100 #define DELETE_SIZE 4 #define TESTDIR "test.dir" static int test_readdir_os2_delete_ret; #define FAILED(d) (printf("failure: readdir [\nFailed for %s - %d = %s\n]\n", d, errno, strerror(errno)), test_readdir_os2_delete_ret = 1, 1) #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #ifdef _WIN32 #define mkdir(d,m) _mkdir(d) #endif static void cleanup(void) { /* I'm a lazy bastard */ if (system("rm -rf " TESTDIR)) { FAILED("system"); } mkdir(TESTDIR, 0700) == 0 || FAILED("mkdir"); } static void create_files(void) { int i; for (i=0;id_name); } if (i == 0) { return 0; } /* delete the first few */ for (j=0; jd_name, ".") == 0 || FAILED("match ."); de = readdir(d); strcmp(de->d_name, "..") == 0 || FAILED("match .."); while (1) { int n = os2_delete(d); if (n == 0) break; total_deleted += n; } closedir(d); fprintf(stderr, "Deleted %d files of %d\n", total_deleted, NUM_FILES); rmdir(TESTDIR) == 0 || FAILED("rmdir"); if (system("rm -rf " TESTDIR) == -1) { FAILED("system"); } return test_readdir_os2_delete_ret; } ctdb-2.5.1.dfsg/lib/replace/test/shared_mmap.c0000644000175000017500000000222512245023514021012 0ustar mathieumathieu/* this tests whether we can use a shared writeable mmap on a file - as needed for the mmap variant of FAST_SHARE_MODES */ #if defined(HAVE_UNISTD_H) #include #endif #include #include #include #include #define DATA "conftest.mmap" #ifndef MAP_FILE #define MAP_FILE 0 #endif main() { int *buf; int i; int fd = open(DATA,O_RDWR|O_CREAT|O_TRUNC,0666); int count=7; if (fd == -1) exit(1); for (i=0;i<10000;i++) { write(fd,&i,sizeof(i)); } close(fd); if (fork() == 0) { fd = open(DATA,O_RDWR); if (fd == -1) exit(1); buf = (int *)mmap(NULL, 10000*sizeof(int), (PROT_READ | PROT_WRITE), MAP_FILE | MAP_SHARED, fd, 0); while (count-- && buf[9124] != 55732) sleep(1); if (count <= 0) exit(1); buf[1763] = 7268; exit(0); } fd = open(DATA,O_RDWR); if (fd == -1) exit(1); buf = (int *)mmap(NULL, 10000*sizeof(int), (PROT_READ | PROT_WRITE), MAP_FILE | MAP_SHARED, fd, 0); if (buf == (int *)-1) exit(1); buf[9124] = 55732; while (count-- && buf[1763] != 7268) sleep(1); unlink(DATA); if (count > 0) exit(0); exit(1); } ctdb-2.5.1.dfsg/lib/replace/xattr.c0000644000175000017500000004746012245023514016727 0ustar mathieumathieu/* Unix SMB/CIFS implementation. replacement routines for xattr implementations Copyright (C) Jeremy Allison 1998-2005 Copyright (C) Timur Bakeyev 2005 Copyright (C) Bjoern Jacke 2006-2007 Copyright (C) Herb Lewis 2003 Copyright (C) Andrew Bartlett 2012 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include "replace.h" #include "system/filesys.h" #include "system/dir.h" /******** Solaris EA helper function prototypes ********/ #ifdef HAVE_ATTROPEN #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP static int solaris_write_xattr(int attrfd, const char *value, size_t size); static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size); static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size); static int solaris_unlinkat(int attrdirfd, const char *name); static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode); static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode); #endif /************************************************************************** Wrappers for extented attribute calls. Based on the Linux package with support for IRIX and (Net|Free)BSD also. Expand as other systems have them. ****************************************************************************/ ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size) { #if defined(HAVE_GETXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return getxattr(path, name, value, size); #else /* So that we do not recursivly call this function */ #undef getxattr int options = 0; return getxattr(path, name, value, size, 0, options); #endif #elif defined(HAVE_GETEA) return getea(path, name, value, size); #elif defined(HAVE_EXTATTR_GET_FILE) char *s; ssize_t retval; int attrnamespace = (strncmp(name, "system", 6) == 0) ? EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1; /* * The BSD implementation has a nasty habit of silently truncating * the returned value to the size of the buffer, so we have to check * that the buffer is large enough to fit the returned value. */ if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) { if (size == 0) { return retval; } else if (retval > size) { errno = ERANGE; return -1; } if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0) return retval; } return -1; #elif defined(HAVE_ATTR_GET) int retval, flags = 0; int valuelength = (int)size; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; retval = attr_get(path, attrname, (char *)value, &valuelength, flags); if (size == 0 && retval == -1 && errno == E2BIG) { return valuelength; } return retval ? retval : valuelength; #elif defined(HAVE_ATTROPEN) ssize_t ret = -1; int attrfd = solaris_attropen(path, name, O_RDONLY, 0); if (attrfd >= 0) { ret = solaris_read_xattr(attrfd, value, size); close(attrfd); } return ret; #else errno = ENOSYS; return -1; #endif } ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size) { #if defined(HAVE_FGETXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return fgetxattr(filedes, name, value, size); #else /* So that we do not recursivly call this function */ #undef fgetxattr int options = 0; return fgetxattr(filedes, name, value, size, 0, options); #endif #elif defined(HAVE_FGETEA) return fgetea(filedes, name, value, size); #elif defined(HAVE_EXTATTR_GET_FD) char *s; ssize_t retval; int attrnamespace = (strncmp(name, "system", 6) == 0) ? EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1; if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) { if (size == 0) { return retval; } else if (retval > size) { errno = ERANGE; return -1; } if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0) return retval; } return -1; #elif defined(HAVE_ATTR_GETF) int retval, flags = 0; int valuelength = (int)size; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags); if (size == 0 && retval == -1 && errno == E2BIG) { return valuelength; } return retval ? retval : valuelength; #elif defined(HAVE_ATTROPEN) ssize_t ret = -1; int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0); if (attrfd >= 0) { ret = solaris_read_xattr(attrfd, value, size); close(attrfd); } return ret; #else errno = ENOSYS; return -1; #endif } #if defined(HAVE_EXTATTR_LIST_FILE) #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1) static struct { int space; const char *name; size_t len; } extattr[] = { { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") }, { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") }, }; typedef union { const char *path; int filedes; } extattr_arg; static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size) { ssize_t list_size, total_size = 0; int i, t, len; char *buf; /* Iterate through extattr(2) namespaces */ for(t = 0; t < ARRAY_SIZE(extattr); t++) { switch(type) { #if defined(HAVE_EXTATTR_LIST_FILE) case 0: list_size = extattr_list_file(arg.path, extattr[t].space, list, size); break; #endif #if defined(HAVE_EXTATTR_LIST_LINK) case 1: list_size = extattr_list_link(arg.path, extattr[t].space, list, size); break; #endif #if defined(HAVE_EXTATTR_LIST_FD) case 2: list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size); break; #endif default: errno = ENOSYS; return -1; } /* Some error happend. Errno should be set by the previous call */ if(list_size < 0) return -1; /* No attributes */ if(list_size == 0) continue; /* XXX: Call with an empty buffer may be used to calculate necessary buffer size. Unfortunately, we can't say, how many attributes were returned, so here is the potential problem with the emulation. */ if(list == NULL) { /* Take the worse case of one char attribute names - two bytes per name plus one more for sanity. */ total_size += list_size + (list_size/2 + 1)*extattr[t].len; continue; } /* Count necessary offset to fit namespace prefixes */ len = 0; for(i = 0; i < list_size; i += list[i] + 1) len += extattr[t].len; total_size += list_size + len; /* Buffer is too small to fit the results */ if(total_size > size) { errno = ERANGE; return -1; } /* Shift results back, so we can prepend prefixes */ buf = (char *)memmove(list + len, list, list_size); for(i = 0; i < list_size; i += len + 1) { len = buf[i]; strncpy(list, extattr[t].name, extattr[t].len + 1); list += extattr[t].len; strncpy(list, buf + i + 1, len); list[len] = '\0'; list += len + 1; } size -= total_size; } return total_size; } #endif #if defined(HAVE_ATTR_LIST) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H)) static char attr_buffer[ATTR_MAX_VALUELEN]; static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags) { int retval = 0, index; attrlist_cursor_t *cursor = 0; int total_size = 0; attrlist_t * al = (attrlist_t *)attr_buffer; attrlist_ent_t *ae; size_t ent_size, left = size; char *bp = list; while (true) { if (filedes) retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); else retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); if (retval) break; for (index = 0; index < al->al_count; index++) { ae = ATTR_ENTRY(attr_buffer, index); ent_size = strlen(ae->a_name) + sizeof("user."); if (left >= ent_size) { strncpy(bp, "user.", sizeof("user.")); strncat(bp, ae->a_name, ent_size - sizeof("user.")); bp += ent_size; left -= ent_size; } else if (size) { errno = ERANGE; retval = -1; break; } total_size += ent_size; } if (al->al_more == 0) break; } if (retval == 0) { flags |= ATTR_ROOT; cursor = 0; while (true) { if (filedes) retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); else retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); if (retval) break; for (index = 0; index < al->al_count; index++) { ae = ATTR_ENTRY(attr_buffer, index); ent_size = strlen(ae->a_name) + sizeof("system."); if (left >= ent_size) { strncpy(bp, "system.", sizeof("system.")); strncat(bp, ae->a_name, ent_size - sizeof("system.")); bp += ent_size; left -= ent_size; } else if (size) { errno = ERANGE; retval = -1; break; } total_size += ent_size; } if (al->al_more == 0) break; } } return (ssize_t)(retval ? retval : total_size); } #endif ssize_t rep_listxattr (const char *path, char *list, size_t size) { #if defined(HAVE_LISTXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return listxattr(path, list, size); #else /* So that we do not recursivly call this function */ #undef listxattr int options = 0; return listxattr(path, list, size, options); #endif #elif defined(HAVE_LISTEA) return listea(path, list, size); #elif defined(HAVE_EXTATTR_LIST_FILE) extattr_arg arg; arg.path = path; return bsd_attr_list(0, arg, list, size); #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H) return irix_attr_list(path, 0, list, size, 0); #elif defined(HAVE_ATTROPEN) ssize_t ret = -1; int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0); if (attrdirfd >= 0) { ret = solaris_list_xattr(attrdirfd, list, size); close(attrdirfd); } return ret; #else errno = ENOSYS; return -1; #endif } ssize_t rep_flistxattr (int filedes, char *list, size_t size) { #if defined(HAVE_FLISTXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return flistxattr(filedes, list, size); #else /* So that we do not recursivly call this function */ #undef flistxattr int options = 0; return flistxattr(filedes, list, size, options); #endif #elif defined(HAVE_FLISTEA) return flistea(filedes, list, size); #elif defined(HAVE_EXTATTR_LIST_FD) extattr_arg arg; arg.filedes = filedes; return bsd_attr_list(2, arg, list, size); #elif defined(HAVE_ATTR_LISTF) return irix_attr_list(NULL, filedes, list, size, 0); #elif defined(HAVE_ATTROPEN) ssize_t ret = -1; int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0); if (attrdirfd >= 0) { ret = solaris_list_xattr(attrdirfd, list, size); close(attrdirfd); } return ret; #else errno = ENOSYS; return -1; #endif } int rep_removexattr (const char *path, const char *name) { #if defined(HAVE_REMOVEXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return removexattr(path, name); #else /* So that we do not recursivly call this function */ #undef removexattr int options = 0; return removexattr(path, name, options); #endif #elif defined(HAVE_REMOVEEA) return removeea(path, name); #elif defined(HAVE_EXTATTR_DELETE_FILE) char *s; int attrnamespace = (strncmp(name, "system", 6) == 0) ? EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1; return extattr_delete_file(path, attrnamespace, attrname); #elif defined(HAVE_ATTR_REMOVE) int flags = 0; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; return attr_remove(path, attrname, flags); #elif defined(HAVE_ATTROPEN) int ret = -1; int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0); if (attrdirfd >= 0) { ret = solaris_unlinkat(attrdirfd, name); close(attrdirfd); } return ret; #else errno = ENOSYS; return -1; #endif } int rep_fremovexattr (int filedes, const char *name) { #if defined(HAVE_FREMOVEXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return fremovexattr(filedes, name); #else /* So that we do not recursivly call this function */ #undef fremovexattr int options = 0; return fremovexattr(filedes, name, options); #endif #elif defined(HAVE_FREMOVEEA) return fremoveea(filedes, name); #elif defined(HAVE_EXTATTR_DELETE_FD) char *s; int attrnamespace = (strncmp(name, "system", 6) == 0) ? EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1; return extattr_delete_fd(filedes, attrnamespace, attrname); #elif defined(HAVE_ATTR_REMOVEF) int flags = 0; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; return attr_removef(filedes, attrname, flags); #elif defined(HAVE_ATTROPEN) int ret = -1; int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0); if (attrdirfd >= 0) { ret = solaris_unlinkat(attrdirfd, name); close(attrdirfd); } return ret; #else errno = ENOSYS; return -1; #endif } int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags) { #if defined(HAVE_SETXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return setxattr(path, name, value, size, flags); #else /* So that we do not recursivly call this function */ #undef setxattr int options = 0; return setxattr(path, name, value, size, 0, options); #endif #elif defined(HAVE_SETEA) return setea(path, name, value, size, flags); #elif defined(HAVE_EXTATTR_SET_FILE) char *s; int retval = 0; int attrnamespace = (strncmp(name, "system", 6) == 0) ? EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1; if (flags) { /* Check attribute existence */ retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0); if (retval < 0) { /* REPLACE attribute, that doesn't exist */ if (flags & XATTR_REPLACE && errno == ENOATTR) { errno = ENOATTR; return -1; } /* Ignore other errors */ } else { /* CREATE attribute, that already exists */ if (flags & XATTR_CREATE) { errno = EEXIST; return -1; } } } retval = extattr_set_file(path, attrnamespace, attrname, value, size); return (retval < 0) ? -1 : 0; #elif defined(HAVE_ATTR_SET) int myflags = 0; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT; if (flags & XATTR_CREATE) myflags |= ATTR_CREATE; if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; return attr_set(path, attrname, (const char *)value, size, myflags); #elif defined(HAVE_ATTROPEN) int ret = -1; int myflags = O_RDWR; int attrfd; if (flags & XATTR_CREATE) myflags |= O_EXCL; if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE); if (attrfd >= 0) { ret = solaris_write_xattr(attrfd, value, size); close(attrfd); } return ret; #else errno = ENOSYS; return -1; #endif } int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags) { #if defined(HAVE_FSETXATTR) #ifndef XATTR_ADDITIONAL_OPTIONS return fsetxattr(filedes, name, value, size, flags); #else /* So that we do not recursivly call this function */ #undef fsetxattr int options = 0; return fsetxattr(filedes, name, value, size, 0, options); #endif #elif defined(HAVE_FSETEA) return fsetea(filedes, name, value, size, flags); #elif defined(HAVE_EXTATTR_SET_FD) char *s; int retval = 0; int attrnamespace = (strncmp(name, "system", 6) == 0) ? EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER; const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1; if (flags) { /* Check attribute existence */ retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0); if (retval < 0) { /* REPLACE attribute, that doesn't exist */ if (flags & XATTR_REPLACE && errno == ENOATTR) { errno = ENOATTR; return -1; } /* Ignore other errors */ } else { /* CREATE attribute, that already exists */ if (flags & XATTR_CREATE) { errno = EEXIST; return -1; } } } retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size); return (retval < 0) ? -1 : 0; #elif defined(HAVE_ATTR_SETF) int myflags = 0; char *attrname = strchr(name,'.') + 1; if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT; if (flags & XATTR_CREATE) myflags |= ATTR_CREATE; if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; return attr_setf(filedes, attrname, (const char *)value, size, myflags); #elif defined(HAVE_ATTROPEN) int ret = -1; int myflags = O_RDWR | O_XATTR; int attrfd; if (flags & XATTR_CREATE) myflags |= O_EXCL; if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE); if (attrfd >= 0) { ret = solaris_write_xattr(attrfd, value, size); close(attrfd); } return ret; #else errno = ENOSYS; return -1; #endif } /************************************************************************** helper functions for Solaris' EA support ****************************************************************************/ #ifdef HAVE_ATTROPEN static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size) { struct stat sbuf; if (fstat(attrfd, &sbuf) == -1) { errno = ENOATTR; return -1; } /* This is to return the current size of the named extended attribute */ if (size == 0) { return sbuf.st_size; } /* check size and read xattr */ if (sbuf.st_size > size) { errno = ERANGE; return -1; } return read(attrfd, value, sbuf.st_size); } static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size) { ssize_t len = 0; DIR *dirp; struct dirent *de; int newfd = dup(attrdirfd); /* CAUTION: The originating file descriptor should not be used again following the call to fdopendir(). For that reason we dup() the file descriptor here to make things more clear. */ dirp = fdopendir(newfd); while ((de = readdir(dirp))) { size_t listlen = strlen(de->d_name) + 1; if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { /* we don't want "." and ".." here: */ continue; } if (size == 0) { /* return the current size of the list of extended attribute names*/ len += listlen; } else { /* check size and copy entrieѕ + nul into list. */ if ((len + listlen) > size) { errno = ERANGE; len = -1; break; } else { strlcpy(list + len, de->d_name, listlen); len += listlen; } } } if (closedir(dirp) == -1) { return -1; } return len; } static int solaris_unlinkat(int attrdirfd, const char *name) { if (unlinkat(attrdirfd, name, 0) == -1) { if (errno == ENOENT) { errno = ENOATTR; } return -1; } return 0; } static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode) { int filedes = attropen(path, attrpath, oflag, mode); if (filedes == -1) { if (errno == EINVAL) { errno = ENOTSUP; } else { errno = ENOATTR; } } return filedes; } static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode) { int filedes = openat(fildes, path, oflag, mode); if (filedes == -1) { if (errno == EINVAL) { errno = ENOTSUP; } else { errno = ENOATTR; } } return filedes; } static int solaris_write_xattr(int attrfd, const char *value, size_t size) { if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) { return 0; } else { return -1; } } #endif /*HAVE_ATTROPEN*/ ctdb-2.5.1.dfsg/lib/replace/replace.h0000644000175000017500000004615312245023514017203 0ustar mathieumathieu/* Unix SMB/CIFS implementation. macros to go along with the lib/replace/ portability layer code Copyright (C) Andrew Tridgell 2005 Copyright (C) Jelmer Vernooij 2006-2008 Copyright (C) Jeremy Allison 2007. ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifndef _LIBREPLACE_REPLACE_H #define _LIBREPLACE_REPLACE_H #ifndef NO_CONFIG_H #include "config.h" #endif #ifdef HAVE_STANDARDS_H #include #endif #include #include #include #include #if defined(_MSC_VER) || defined(__MINGW32__) #include "win32_replace.h" #endif #ifdef HAVE_INTTYPES_H #define __STDC_FORMAT_MACROS #include #elif HAVE_STDINT_H #include /* force off HAVE_INTTYPES_H so that roken doesn't try to include both, which causes a warning storm on irix */ #undef HAVE_INTTYPES_H #endif #ifdef HAVE_MALLOC_H #include #endif #ifndef __PRI64_PREFIX # if __WORDSIZE == 64 && ! defined __APPLE__ # define __PRI64_PREFIX "l" # else # define __PRI64_PREFIX "ll" # endif #endif /* Decimal notation. */ #ifndef PRId8 # define PRId8 "d" #endif #ifndef PRId16 # define PRId16 "d" #endif #ifndef PRId32 # define PRId32 "d" #endif #ifndef PRId64 # define PRId64 __PRI64_PREFIX "d" #endif #ifndef PRIi8 # define PRIi8 "i" #endif #ifndef PRIi16 # define PRIi16 "i" #endif #ifndef PRIi32 # define PRIi32 "i" #endif #ifndef PRIi64 # define PRIi64 __PRI64_PREFIX "i" #endif #ifndef PRIu8 # define PRIu8 "u" #endif #ifndef PRIu16 # define PRIu16 "u" #endif #ifndef PRIu32 # define PRIu32 "u" #endif #ifndef PRIu64 # define PRIu64 __PRI64_PREFIX "u" #endif #ifndef SCNd8 # define SCNd8 "hhd" #endif #ifndef SCNd16 # define SCNd16 "hd" #endif #ifndef SCNd32 # define SCNd32 "d" #endif #ifndef SCNd64 # define SCNd64 __PRI64_PREFIX "d" #endif #ifndef SCNi8 # define SCNi8 "hhi" #endif #ifndef SCNi16 # define SCNi16 "hi" #endif #ifndef SCNi32 # define SCNi32 "i" #endif #ifndef SCNi64 # define SCNi64 __PRI64_PREFIX "i" #endif #ifndef SCNu8 # define SCNu8 "hhu" #endif #ifndef SCNu16 # define SCNu16 "hu" #endif #ifndef SCNu32 # define SCNu32 "u" #endif #ifndef SCNu64 # define SCNu64 __PRI64_PREFIX "u" #endif #ifdef HAVE_BSD_STRING_H #include #endif #ifdef HAVE_BSD_UNISTD_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SETPROCTITLE_H #include #endif #if STDC_HEADERS #include #include #endif #ifdef HAVE_LINUX_TYPES_H /* * This is needed as some broken header files require this to be included early */ #include #endif #ifndef HAVE_STRERROR extern char *sys_errlist[]; #define strerror(i) sys_errlist[i] #endif #ifndef HAVE_ERRNO_DECL extern int errno; #endif #ifndef HAVE_STRDUP #define strdup rep_strdup char *rep_strdup(const char *s); #endif #ifndef HAVE_MEMMOVE #define memmove rep_memmove void *rep_memmove(void *dest,const void *src,int size); #endif #ifndef HAVE_MEMMEM #define memmem rep_memmem void *rep_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); #endif #ifndef HAVE_MEMALIGN #define memalign rep_memalign void *rep_memalign(size_t boundary, size_t size); #endif #ifndef HAVE_MKTIME #define mktime rep_mktime /* prototype is in "system/time.h" */ #endif #ifndef HAVE_TIMEGM #define timegm rep_timegm /* prototype is in "system/time.h" */ #endif #ifndef HAVE_UTIME #define utime rep_utime /* prototype is in "system/time.h" */ #endif #ifndef HAVE_UTIMES #define utimes rep_utimes /* prototype is in "system/time.h" */ #endif #ifndef HAVE_STRLCPY #define strlcpy rep_strlcpy size_t rep_strlcpy(char *d, const char *s, size_t bufsize); #endif #ifndef HAVE_STRLCAT #define strlcat rep_strlcat size_t rep_strlcat(char *d, const char *s, size_t bufsize); #endif #if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP)) #undef HAVE_STRNDUP #define strndup rep_strndup char *rep_strndup(const char *s, size_t n); #endif #if (defined(BROKEN_STRNLEN) || !defined(HAVE_STRNLEN)) #undef HAVE_STRNLEN #define strnlen rep_strnlen size_t rep_strnlen(const char *s, size_t n); #endif #if !HAVE_DECL_ENVIRON #ifdef __APPLE__ #include #define environ (*_NSGetEnviron()) #else extern char **environ; #endif #endif #ifndef HAVE_SETENV #define setenv rep_setenv int rep_setenv(const char *name, const char *value, int overwrite); #else #ifndef HAVE_SETENV_DECL int setenv(const char *name, const char *value, int overwrite); #endif #endif #ifndef HAVE_UNSETENV #define unsetenv rep_unsetenv int rep_unsetenv(const char *name); #endif #ifndef HAVE_SETEUID #define seteuid rep_seteuid int rep_seteuid(uid_t); #endif #ifndef HAVE_SETEGID #define setegid rep_setegid int rep_setegid(gid_t); #endif #if (defined(USE_SETRESUID) && !defined(HAVE_SETRESUID_DECL)) /* stupid glibc */ int setresuid(uid_t ruid, uid_t euid, uid_t suid); #endif #if (defined(USE_SETRESUID) && !defined(HAVE_SETRESGID_DECL)) int setresgid(gid_t rgid, gid_t egid, gid_t sgid); #endif #ifndef HAVE_CHOWN #define chown rep_chown int rep_chown(const char *path, uid_t uid, gid_t gid); #endif #ifndef HAVE_CHROOT #define chroot rep_chroot int rep_chroot(const char *dirname); #endif #ifndef HAVE_LINK #define link rep_link int rep_link(const char *oldpath, const char *newpath); #endif #ifndef HAVE_READLINK #define readlink rep_readlink ssize_t rep_readlink(const char *path, char *buf, size_t bufsize); #endif #ifndef HAVE_SYMLINK #define symlink rep_symlink int rep_symlink(const char *oldpath, const char *newpath); #endif #ifndef HAVE_REALPATH #define realpath rep_realpath char *rep_realpath(const char *path, char *resolved_path); #endif #ifndef HAVE_LCHOWN #define lchown rep_lchown int rep_lchown(const char *fname,uid_t uid,gid_t gid); #endif #ifdef HAVE_UNIX_H #include #endif #ifndef HAVE_SETLINEBUF #define setlinebuf rep_setlinebuf void rep_setlinebuf(FILE *); #endif #ifndef HAVE_STRCASESTR #define strcasestr rep_strcasestr char *rep_strcasestr(const char *haystack, const char *needle); #endif #ifndef HAVE_STRTOK_R #define strtok_r rep_strtok_r char *rep_strtok_r(char *s, const char *delim, char **save_ptr); #endif #ifndef HAVE_STRTOLL #define strtoll rep_strtoll long long int rep_strtoll(const char *str, char **endptr, int base); #else #ifdef HAVE_BSD_STRTOLL #define strtoll rep_strtoll long long int rep_strtoll(const char *str, char **endptr, int base); #endif #endif #ifndef HAVE_STRTOULL #define strtoull rep_strtoull unsigned long long int rep_strtoull(const char *str, char **endptr, int base); #else #ifdef HAVE_BSD_STRTOLL /* yes, it's not HAVE_BSD_STRTOULL */ #define strtoull rep_strtoull unsigned long long int rep_strtoull(const char *str, char **endptr, int base); #endif #endif #ifndef HAVE_FTRUNCATE #define ftruncate rep_ftruncate int rep_ftruncate(int,off_t); #endif #ifndef HAVE_INITGROUPS #define initgroups rep_initgroups int rep_initgroups(char *name, gid_t id); #endif #if !defined(HAVE_BZERO) && defined(HAVE_MEMSET) #define bzero(a,b) memset((a),'\0',(b)) #endif #ifndef HAVE_DLERROR #define dlerror rep_dlerror char *rep_dlerror(void); #endif #ifndef HAVE_DLOPEN #define dlopen rep_dlopen #ifdef DLOPEN_TAKES_UNSIGNED_FLAGS void *rep_dlopen(const char *name, unsigned int flags); #else void *rep_dlopen(const char *name, int flags); #endif #endif #ifndef HAVE_DLSYM #define dlsym rep_dlsym void *rep_dlsym(void *handle, const char *symbol); #endif #ifndef HAVE_DLCLOSE #define dlclose rep_dlclose int rep_dlclose(void *handle); #endif #ifndef HAVE_SOCKETPAIR #define socketpair rep_socketpair /* prototype is in system/network.h */ #endif #ifndef PRINTF_ATTRIBUTE #if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) /** Use gcc attribute to check printf fns. a1 is the 1-based index of * the parameter containing the format, and a2 the index of the first * argument. Note that some gcc 2.x versions don't handle this * properly **/ #define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) #else #define PRINTF_ATTRIBUTE(a1, a2) #endif #endif #ifndef _DEPRECATED_ #if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 ) #define _DEPRECATED_ __attribute__ ((deprecated)) #else #define _DEPRECATED_ #endif #endif #if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF) #define vdprintf rep_vdprintf int rep_vdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0); #endif #if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF) #define dprintf rep_dprintf int rep_dprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3); #endif #if !defined(HAVE_VASPRINTF) || !defined(HAVE_C99_VSNPRINTF) #define vasprintf rep_vasprintf int rep_vasprintf(char **ptr, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0); #endif #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) #define snprintf rep_snprintf int rep_snprintf(char *,size_t ,const char *, ...) PRINTF_ATTRIBUTE(3,4); #endif #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) #define vsnprintf rep_vsnprintf int rep_vsnprintf(char *,size_t ,const char *, va_list ap) PRINTF_ATTRIBUTE(3,0); #endif #if !defined(HAVE_ASPRINTF) || !defined(HAVE_C99_VSNPRINTF) #define asprintf rep_asprintf int rep_asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3); #endif #if !defined(HAVE_C99_VSNPRINTF) #ifdef REPLACE_BROKEN_PRINTF /* * We do not redefine printf by default * as it breaks the build if system headers * use __attribute__((format(printf, 3, 0))) * instead of __attribute__((format(__printf__, 3, 0))) */ #define printf rep_printf #endif int rep_printf(const char *, ...) PRINTF_ATTRIBUTE(1,2); #endif #if !defined(HAVE_C99_VSNPRINTF) #define fprintf rep_fprintf int rep_fprintf(FILE *stream, const char *, ...) PRINTF_ATTRIBUTE(2,3); #endif #ifndef HAVE_VSYSLOG #ifdef HAVE_SYSLOG #define vsyslog rep_vsyslog void rep_vsyslog (int facility_priority, const char *format, va_list arglist) PRINTF_ATTRIBUTE(2,0); #endif #endif /* we used to use these fns, but now we have good replacements for snprintf and vsnprintf */ #define slprintf snprintf #ifndef HAVE_VA_COPY #undef va_copy #ifdef HAVE___VA_COPY #define va_copy(dest, src) __va_copy(dest, src) #else #define va_copy(dest, src) (dest) = (src) #endif #endif #ifndef HAVE_VOLATILE #define volatile #endif #ifndef HAVE_COMPARISON_FN_T typedef int (*comparison_fn_t)(const void *, const void *); #endif #ifndef HAVE_WORKING_STRPTIME #define strptime rep_strptime struct tm; char *rep_strptime(const char *buf, const char *format, struct tm *tm); #endif #ifndef HAVE_DUP2 #define dup2 rep_dup2 int rep_dup2(int oldfd, int newfd); #endif /* Load header file for dynamic linking stuff */ #ifdef HAVE_DLFCN_H #include #endif #ifndef RTLD_LAZY #define RTLD_LAZY 0 #endif #ifndef RTLD_NOW #define RTLD_NOW 0 #endif #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif #ifndef HAVE_SECURE_MKSTEMP #define mkstemp(path) rep_mkstemp(path) int rep_mkstemp(char *temp); #endif #ifndef HAVE_MKDTEMP #define mkdtemp rep_mkdtemp char *rep_mkdtemp(char *template); #endif #ifndef HAVE_PREAD #define pread rep_pread ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset); #define LIBREPLACE_PREAD_REPLACED 1 #else #define LIBREPLACE_PREAD_NOT_REPLACED 1 #endif #ifndef HAVE_PWRITE #define pwrite rep_pwrite ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset); #define LIBREPLACE_PWRITE_REPLACED 1 #else #define LIBREPLACE_PWRITE_NOT_REPLACED 1 #endif #if !defined(HAVE_INET_NTOA) || defined(REPLACE_INET_NTOA) #define inet_ntoa rep_inet_ntoa /* prototype is in "system/network.h" */ #endif #ifndef HAVE_INET_PTON #define inet_pton rep_inet_pton /* prototype is in "system/network.h" */ #endif #ifndef HAVE_INET_NTOP #define inet_ntop rep_inet_ntop /* prototype is in "system/network.h" */ #endif #ifndef HAVE_INET_ATON #define inet_aton rep_inet_aton /* prototype is in "system/network.h" */ #endif #ifndef HAVE_CONNECT #define connect rep_connect /* prototype is in "system/network.h" */ #endif #ifndef HAVE_GETHOSTBYNAME #define gethostbyname rep_gethostbyname /* prototype is in "system/network.h" */ #endif #ifndef HAVE_GETIFADDRS #define getifaddrs rep_getifaddrs /* prototype is in "system/network.h" */ #endif #ifndef HAVE_FREEIFADDRS #define freeifaddrs rep_freeifaddrs /* prototype is in "system/network.h" */ #endif #ifndef HAVE_GET_CURRENT_DIR_NAME #define get_current_dir_name rep_get_current_dir_name char *rep_get_current_dir_name(void); #endif #ifndef HAVE_STRERROR_R #define strerror_r rep_strerror_r int rep_strerror_r(int errnum, char *buf, size_t buflen); #endif #if !defined(HAVE_CLOCK_GETTIME) #define clock_gettime rep_clock_gettime #endif #ifdef HAVE_LIMITS_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif /* The extra casts work around common compiler bugs. */ #define _TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) /* The outer cast is needed to work around a bug in Cray C 5.0.3.0. It is necessary at least when t == time_t. */ #define _TYPE_MINIMUM(t) ((t) (_TYPE_SIGNED (t) \ ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) #define _TYPE_MAXIMUM(t) ((t) (~ (t) 0 - _TYPE_MINIMUM (t))) #ifndef UINT16_MAX #define UINT16_MAX 65535 #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef UINT64_MAX #define UINT64_MAX ((uint64_t)-1) #endif #ifndef INT64_MAX #define INT64_MAX 9223372036854775807LL #endif #ifndef CHAR_BIT #define CHAR_BIT 8 #endif #ifndef INT32_MAX #define INT32_MAX _TYPE_MAXIMUM(int32_t) #endif #ifdef HAVE_STDBOOL_H #include #endif #if !defined(HAVE_BOOL) #ifdef HAVE__Bool #define bool _Bool #else typedef int bool; #endif #endif #if !defined(HAVE_INTPTR_T) typedef long long intptr_t ; #endif #if !defined(HAVE_UINTPTR_T) typedef unsigned long long uintptr_t ; #endif #if !defined(HAVE_PTRDIFF_T) typedef unsigned long long ptrdiff_t ; #endif /* * to prevent from doing a redefine of 'bool' * * IRIX, HPUX, MacOS 10 and Solaris need BOOL_DEFINED * Tru64 needs _BOOL_EXISTS * AIX needs _BOOL,_TRUE,_FALSE */ #ifndef BOOL_DEFINED #define BOOL_DEFINED #endif #ifndef _BOOL_EXISTS #define _BOOL_EXISTS #endif #ifndef _BOOL #define _BOOL #endif #ifndef __bool_true_false_are_defined #define __bool_true_false_are_defined #endif #ifndef true #define true (1) #endif #ifndef false #define false (0) #endif #ifndef _TRUE #define _TRUE true #endif #ifndef _FALSE #define _FALSE false #endif #ifndef HAVE_FUNCTION_MACRO #ifdef HAVE_func_MACRO #define __FUNCTION__ __func__ #else #define __FUNCTION__ ("") #endif #endif #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #endif #if !defined(HAVE_VOLATILE) #define volatile #endif /** this is a warning hack. The idea is to use this everywhere that we get the "discarding const" warning from gcc. That doesn't actually fix the problem of course, but it means that when we do get to cleaning them up we can do it by searching the code for discard_const. It also means that other error types aren't as swamped by the noise of hundreds of const warnings, so we are more likely to notice when we get new errors. Please only add more uses of this macro when you find it _really_ hard to fix const warnings. Our aim is to eventually use this function in only a very few places. Also, please call this via the discard_const_p() macro interface, as that makes the return type safe. */ #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) /** Type-safe version of discard_const */ #define discard_const_p(type, ptr) ((type *)discard_const(ptr)) #ifndef __STRING #define __STRING(x) #x #endif #ifndef __STRINGSTRING #define __STRINGSTRING(x) __STRING(x) #endif #ifndef __LINESTR__ #define __LINESTR__ __STRINGSTRING(__LINE__) #endif #ifndef __location__ #define __location__ __FILE__ ":" __LINESTR__ #endif /** * zero a structure */ #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) /** * zero a structure given a pointer to the structure */ #define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0) /** * zero a structure given a pointer to the structure - no zero check */ #define ZERO_STRUCTPN(x) memset((char *)(x), 0, sizeof(*(x))) /* zero an array - note that sizeof(array) must work - ie. it must not be a pointer */ #define ZERO_ARRAY(x) memset((char *)(x), 0, sizeof(x)) /** * work out how many elements there are in a static array */ #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) /** * pointer difference macro */ #define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2))) #if MMAP_BLACKLIST #undef HAVE_MMAP #endif #ifdef __COMPAR_FN_T #define QSORT_CAST (__compar_fn_t) #endif #ifndef QSORT_CAST #define QSORT_CAST (int (*)(const void *, const void *)) #endif #ifndef PATH_MAX #define PATH_MAX 1024 #endif #ifndef MAX_DNS_NAME_LENGTH #define MAX_DNS_NAME_LENGTH 256 /* Actually 255 but +1 for terminating null. */ #endif #ifndef HAVE_CRYPT char *ufc_crypt(const char *key, const char *salt); #define crypt ufc_crypt #else #ifdef HAVE_CRYPT_H #include #endif #endif /* these macros gain us a few percent of speed on gcc */ #if (__GNUC__ >= 3) /* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 as its first argument */ #ifndef likely #define likely(x) __builtin_expect(!!(x), 1) #endif #ifndef unlikely #define unlikely(x) __builtin_expect(!!(x), 0) #endif #else #ifndef likely #define likely(x) (x) #endif #ifndef unlikely #define unlikely(x) (x) #endif #endif #ifndef HAVE_FDATASYNC #define fdatasync(fd) fsync(fd) #elif !defined(HAVE_DECL_FDATASYNC) int fdatasync(int ); #endif /* these are used to mark symbols as local to a shared lib, or * publicly available via the shared lib API */ #ifndef _PUBLIC_ #ifdef HAVE_VISIBILITY_ATTR #define _PUBLIC_ __attribute__((visibility("default"))) #else #define _PUBLIC_ #endif #endif #ifndef _PRIVATE_ #ifdef HAVE_VISIBILITY_ATTR # define _PRIVATE_ __attribute__((visibility("hidden"))) #else # define _PRIVATE_ #endif #endif #ifndef HAVE_POLL #define poll rep_poll /* prototype is in "system/network.h" */ #endif #ifndef HAVE_GETPEEREID #define getpeereid rep_getpeereid int rep_getpeereid(int s, uid_t *uid, gid_t *gid); #endif #ifndef HAVE_USLEEP #define usleep rep_usleep typedef long useconds_t; int usleep(useconds_t); #endif #ifndef HAVE_SETPROCTITLE #define setproctitle rep_setproctitle void rep_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2); #endif #endif /* _LIBREPLACE_REPLACE_H */ ctdb-2.5.1.dfsg/lib/replace/getifaddrs.c0000644000175000017500000001723512245023514017676 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Samba utility functions Copyright (C) Andrew Tridgell 1998 Copyright (C) Jeremy Allison 2007 Copyright (C) Jelmer Vernooij 2007 This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #define SOCKET_WRAPPER_NOT_REPLACE #include "replace.h" #include "system/network.h" #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifndef SIOCGIFCONF #ifdef HAVE_SYS_SOCKIO_H #include #endif #endif #ifdef HAVE_IFACE_GETIFADDRS #define _FOUND_IFACE_ANY #else void rep_freeifaddrs(struct ifaddrs *ifp) { if (ifp != NULL) { free(ifp->ifa_name); free(ifp->ifa_addr); free(ifp->ifa_netmask); free(ifp->ifa_dstaddr); freeifaddrs(ifp->ifa_next); free(ifp); } } static struct sockaddr *sockaddr_dup(struct sockaddr *sa) { struct sockaddr *ret; socklen_t socklen; #ifdef HAVE_SOCKADDR_SA_LEN socklen = sa->sa_len; #else socklen = sizeof(struct sockaddr_storage); #endif ret = calloc(1, socklen); if (ret == NULL) return NULL; memcpy(ret, sa, socklen); return ret; } #endif #if HAVE_IFACE_IFCONF /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2. It probably also works on any BSD style system. */ int rep_getifaddrs(struct ifaddrs **ifap) { struct ifconf ifc; char buff[8192]; int fd, i, n; struct ifreq *ifr=NULL; struct ifaddrs *curif; struct ifaddrs *lastif = NULL; *ifap = NULL; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { close(fd); return -1; } ifr = ifc.ifc_req; n = ifc.ifc_len / sizeof(struct ifreq); /* Loop through interfaces, looking for given IP address */ for (i=n-1; i>=0; i--) { if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) { freeifaddrs(*ifap); return -1; } curif = calloc(1, sizeof(struct ifaddrs)); curif->ifa_name = strdup(ifr[i].ifr_name); curif->ifa_flags = ifr[i].ifr_flags; curif->ifa_dstaddr = NULL; curif->ifa_data = NULL; curif->ifa_next = NULL; curif->ifa_addr = NULL; if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) { curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr); } curif->ifa_netmask = NULL; if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) { curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr); } if (lastif == NULL) { *ifap = curif; } else { lastif->ifa_next = curif; } lastif = curif; } close(fd); return 0; } #define _FOUND_IFACE_ANY #endif /* HAVE_IFACE_IFCONF */ #ifdef HAVE_IFACE_IFREQ #ifndef I_STR #include #endif /**************************************************************************** this should cover most of the streams based systems Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code ****************************************************************************/ int rep_getifaddrs(struct ifaddrs **ifap) { struct ifreq ifreq; struct strioctl strioctl; char buff[8192]; int fd, i, n; struct ifreq *ifr=NULL; struct ifaddrs *curif; struct ifaddrs *lastif = NULL; *ifap = NULL; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } strioctl.ic_cmd = SIOCGIFCONF; strioctl.ic_dp = buff; strioctl.ic_len = sizeof(buff); if (ioctl(fd, I_STR, &strioctl) < 0) { close(fd); return -1; } /* we can ignore the possible sizeof(int) here as the resulting number of interface structures won't change */ n = strioctl.ic_len / sizeof(struct ifreq); /* we will assume that the kernel returns the length as an int at the start of the buffer if the offered size is a multiple of the structure size plus an int */ if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) { ifr = (struct ifreq *)(buff + sizeof(int)); } else { ifr = (struct ifreq *)buff; } /* Loop through interfaces */ for (i = 0; iifa_next = curif; } strioctl.ic_cmd = SIOCGIFFLAGS; strioctl.ic_dp = (char *)&ifreq; strioctl.ic_len = sizeof(struct ifreq); if (ioctl(fd, I_STR, &strioctl) != 0) { freeifaddrs(*ifap); return -1; } curif->ifa_flags = ifreq.ifr_flags; strioctl.ic_cmd = SIOCGIFADDR; strioctl.ic_dp = (char *)&ifreq; strioctl.ic_len = sizeof(struct ifreq); if (ioctl(fd, I_STR, &strioctl) != 0) { freeifaddrs(*ifap); return -1; } curif->ifa_name = strdup(ifreq.ifr_name); curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr); curif->ifa_dstaddr = NULL; curif->ifa_data = NULL; curif->ifa_next = NULL; curif->ifa_netmask = NULL; strioctl.ic_cmd = SIOCGIFNETMASK; strioctl.ic_dp = (char *)&ifreq; strioctl.ic_len = sizeof(struct ifreq); if (ioctl(fd, I_STR, &strioctl) != 0) { freeifaddrs(*ifap); return -1; } curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr); lastif = curif; } close(fd); return 0; } #define _FOUND_IFACE_ANY #endif /* HAVE_IFACE_IFREQ */ #ifdef HAVE_IFACE_AIX /**************************************************************************** this one is for AIX (tested on 4.2) ****************************************************************************/ int rep_getifaddrs(struct ifaddrs **ifap) { char buff[8192]; int fd, i; struct ifconf ifc; struct ifreq *ifr=NULL; struct ifaddrs *curif; struct ifaddrs *lastif = NULL; *ifap = NULL; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { close(fd); return -1; } ifr = ifc.ifc_req; /* Loop through interfaces */ i = ifc.ifc_len; while (i > 0) { unsigned int inc; inc = ifr->ifr_addr.sa_len; if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { freeaddrinfo(*ifap); return -1; } curif = calloc(1, sizeof(struct ifaddrs)); if (lastif == NULL) { *ifap = curif; } else { lastif->ifa_next = curif; } curif->ifa_name = strdup(ifr->ifr_name); curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr); curif->ifa_dstaddr = NULL; curif->ifa_data = NULL; curif->ifa_netmask = NULL; curif->ifa_next = NULL; if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { freeaddrinfo(*ifap); return -1; } curif->ifa_flags = ifr->ifr_flags; if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { freeaddrinfo(*ifap); return -1; } curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr); lastif = curif; next: /* * Patch from Archie Cobbs (archie@whistle.com). The * addresses in the SIOCGIFCONF interface list have a * minimum size. Usually this doesn't matter, but if * your machine has tunnel interfaces, etc. that have * a zero length "link address", this does matter. */ if (inc < sizeof(ifr->ifr_addr)) inc = sizeof(ifr->ifr_addr); inc += IFNAMSIZ; ifr = (struct ifreq*) (((char*) ifr) + inc); i -= inc; } close(fd); return 0; } #define _FOUND_IFACE_ANY #endif /* HAVE_IFACE_AIX */ #ifndef _FOUND_IFACE_ANY int rep_getifaddrs(struct ifaddrs **ifap) { errno = ENOSYS; return -1; } #endif ctdb-2.5.1.dfsg/lib/replace/inet_pton.c0000644000175000017500000001201012245023514017543 0ustar mathieumathieu/* * Copyright (C) 1996-2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "replace.h" #include "system/network.h" #define NS_INT16SZ 2 #define NS_INADDRSZ 4 #define NS_IN6ADDRSZ 16 /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static int inet_pton4(const char *src, unsigned char *dst); #ifdef AF_INET6 static int inet_pton6(const char *src, unsigned char *dst); #endif /* int * inet_pton(af, src, dst) * convert from presentation format (which usually means ASCII printable) * to network format (which is usually some kind of binary format). * return: * 1 if the address was valid for the specified address family * 0 if the address wasn't valid (`dst' is untouched in this case) * -1 if some other error occurred (`dst' is untouched in this case, too) * author: * Paul Vixie, 1996. */ int rep_inet_pton(int af, const char *src, void *dst) { switch (af) { case AF_INET: return (inet_pton4(src, dst)); #ifdef AF_INET6 case AF_INET6: return (inet_pton6(src, dst)); #endif default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. * return: * 1 if `src' is a valid dotted quad, else 0. * notice: * does not touch `dst' unless it's returning 1. * author: * Paul Vixie, 1996. */ static int inet_pton4(src, dst) const char *src; unsigned char *dst; { static const char digits[] = "0123456789"; int saw_digit, octets, ch; unsigned char tmp[NS_INADDRSZ], *tp; saw_digit = 0; octets = 0; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { unsigned int new = *tp * 10 + (pch - digits); if (new > 255) return (0); *tp = new; if (! saw_digit) { if (++octets > 4) return (0); saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return (0); *++tp = 0; saw_digit = 0; } else return (0); } if (octets < 4) return (0); memcpy(dst, tmp, NS_INADDRSZ); return (1); } /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning 1. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ #ifdef AF_INET6 static int inet_pton6(src, dst) const char *src; unsigned char *dst; { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit; unsigned int val; memset((tp = tmp), '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } if (tp + NS_INT16SZ > endp) return (0); *tp++ = (unsigned char) (val >> 8) & 0xff; *tp++ = (unsigned char) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) { tp += NS_INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } return (0); } if (saw_xdigit) { if (tp + NS_INT16SZ > endp) return (0); *tp++ = (unsigned char) (val >> 8) & 0xff; *tp++ = (unsigned char) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, NS_IN6ADDRSZ); return (1); } #endif ctdb-2.5.1.dfsg/lib/replace/strptime.m40000644000175000017500000000113012245023514017512 0ustar mathieumathieuAC_CHECK_FUNCS(strptime) AC_CHECK_DECLS(strptime, [], [], [#include ]) AC_CACHE_CHECK([whether strptime is available and works],libreplace_cv_STRPTIME_OK,[ AC_TRY_RUN([ #define LIBREPLACE_CONFIGURE_TEST_STRPTIME #include "$libreplacedir/test/strptime.c" ], [libreplace_cv_STRPTIME_OK=yes], [libreplace_cv_STRPTIME_OK=no], [libreplace_cv_STRPTIME_OK="assuming not"]) ]) if test x"$libreplace_cv_STRPTIME_OK" != x"yes"; then LIBREPLACEOBJ="${LIBREPLACEOBJ} $libreplacedir/strptime.o" else AC_DEFINE(HAVE_WORKING_STRPTIME,1,[Whether strptime is working correct]) fi ctdb-2.5.1.dfsg/lib/replace/install-sh0000755000175000017500000001124512245023514017415 0ustar mathieumathieu#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 ctdb-2.5.1.dfsg/lib/replace/socketpair.c0000644000175000017500000000250112245023514017714 0ustar mathieumathieu/* * Unix SMB/CIFS implementation. * replacement routines for broken systems * Copyright (C) Jelmer Vernooij 2006 * Copyright (C) Michael Adam 2008 * * ** NOTE! The following LGPL license applies to the replace * ** library. This does NOT imply that all of Samba is released * ** under the LGPL * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include "replace.h" #include "system/network.h" int rep_socketpair(int d, int type, int protocol, int sv[2]) { if (d != AF_UNIX) { errno = EAFNOSUPPORT; return -1; } if (protocol != 0) { errno = EPROTONOSUPPORT; return -1; } if (type != SOCK_STREAM) { errno = EOPNOTSUPP; return -1; } return pipe(sv); } ctdb-2.5.1.dfsg/lib/replace/inet_ntoa.c0000644000175000017500000000247512245023514017542 0ustar mathieumathieu/* * Unix SMB/CIFS implementation. * replacement routines for broken systems * Copyright (C) Andrew Tridgell 2003 * Copyright (C) Michael Adam 2008 * * ** NOTE! The following LGPL license applies to the replace * ** library. This does NOT imply that all of Samba is released * ** under the LGPL * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include "replace.h" #include "system/network.h" /** * NOTE: this is not thread safe, but it can't be, either * since it returns a pointer to static memory. */ char *rep_inet_ntoa(struct in_addr ip) { uint8_t *p = (uint8_t *)&ip.s_addr; static char buf[18]; slprintf(buf, 17, "%d.%d.%d.%d", (int)p[0], (int)p[1], (int)p[2], (int)p[3]); return buf; } ctdb-2.5.1.dfsg/lib/replace/poll.c0000644000175000017500000000640512245023514016525 0ustar mathieumathieu/* Unix SMB/CIFS implementation. poll.c - poll wrapper This file is based on code from libssh (LGPLv2.1+ at the time it was downloaded), thus the following copyrights: Copyright (c) 2009-2010 by Andreas Schneider Copyright (c) 2003-2009 by Aris Adamantiadis Copyright (c) 2009 Aleksandar Kanchev Copyright (C) Volker Lendecke 2011 ** NOTE! The following LGPL license applies to the replace ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include "replace.h" #include "system/select.h" #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif int rep_poll(struct pollfd *fds, nfds_t nfds, int timeout) { fd_set rfds, wfds, efds; struct timeval tv, *ptv; int max_fd; int rc; nfds_t i; if ((fds == NULL) && (nfds != 0)) { errno = EFAULT; return -1; } FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); rc = 0; max_fd = 0; /* compute fd_sets and find largest descriptor */ for (i = 0; i < nfds; i++) { if ((fds[i].fd < 0) || (fds[i].fd >= FD_SETSIZE)) { fds[i].revents = POLLNVAL; continue; } if (fds[i].events & (POLLIN | POLLRDNORM)) { FD_SET(fds[i].fd, &rfds); } if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) { FD_SET(fds[i].fd, &wfds); } if (fds[i].events & (POLLPRI | POLLRDBAND)) { FD_SET(fds[i].fd, &efds); } if (fds[i].fd > max_fd && (fds[i].events & (POLLIN | POLLOUT | POLLPRI | POLLRDNORM | POLLRDBAND | POLLWRNORM | POLLWRBAND))) { max_fd = fds[i].fd; } } if (timeout < 0) { ptv = NULL; } else { ptv = &tv; if (timeout == 0) { tv.tv_sec = 0; tv.tv_usec = 0; } else { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; } } rc = select(max_fd + 1, &rfds, &wfds, &efds, ptv); if (rc < 0) { return -1; } for (rc = 0, i = 0; i < nfds; i++) { if ((fds[i].fd < 0) || (fds[i].fd >= FD_SETSIZE)) { continue; } fds[i].revents = 0; if (FD_ISSET(fds[i].fd, &rfds)) { int err = errno; int available = 0; int ret; /* support for POLLHUP */ ret = ioctl(fds[i].fd, FIONREAD, &available); if ((ret == -1) || (available == 0)) { fds[i].revents |= POLLHUP; } else { fds[i].revents |= fds[i].events & (POLLIN | POLLRDNORM); } errno = err; } if (FD_ISSET(fds[i].fd, &wfds)) { fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND); } if (FD_ISSET(fds[i].fd, &efds)) { fds[i].revents |= fds[i].events & (POLLPRI | POLLRDBAND); } if (fds[i].revents & ~POLLHUP) { rc++; } } return rc; } ctdb-2.5.1.dfsg/lib/replace/socket.c0000644000175000017500000000202512245023514017041 0ustar mathieumathieu/* * Unix SMB/CIFS implementation. * * Dummy replacements for socket functions. * * Copyright (C) Michael Adam 2008 * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . */ #include "replace.h" #include "system/network.h" int rep_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) { errno = ENOSYS; return -1; } struct hostent *rep_gethostbyname(const char *name) { errno = ENOSYS; return NULL; } ctdb-2.5.1.dfsg/lib/replace/timegm.c0000644000175000017500000000476412245023514017047 0ustar mathieumathieu/* * Copyright (c) 1997 Kungliga Tekniska Hgskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* adapted for Samba4 by Andrew Tridgell */ #include "replace.h" #include "system/time.h" static int is_leap(unsigned y) { y += 1900; return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); } time_t rep_timegm(struct tm *tm) { static const unsigned ndays[2][12] ={ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; time_t res = 0; unsigned i; if (tm->tm_mon > 12 || tm->tm_mon < 0 || tm->tm_mday > 31 || tm->tm_min > 60 || tm->tm_sec > 60 || tm->tm_hour > 24) { /* invalid tm structure */ return 0; } for (i = 70; i < tm->tm_year; ++i) res += is_leap(i) ? 366 : 365; for (i = 0; i < tm->tm_mon; ++i) res += ndays[is_leap(tm->tm_year)][i]; res += tm->tm_mday - 1; res *= 24; res += tm->tm_hour; res *= 60; res += tm->tm_min; res *= 60; res += tm->tm_sec; return res; } ctdb-2.5.1.dfsg/lib/replace/inet_aton.c0000644000175000017500000000223212245023514017531 0ustar mathieumathieu/* * Unix SMB/CIFS implementation. * replacement functions * Copyright (C) Michael Adam 2008 * * ** NOTE! The following LGPL license applies to the replace * ** library. This does NOT imply that all of Samba is released * ** under the LGPL * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include "replace.h" #include "system/network.h" /** * We know that we have inet_pton from earlier libreplace checks. */ int rep_inet_aton(const char *src, struct in_addr *dst) { return (inet_pton(AF_INET, src, dst) > 0) ? 1 : 0; } ctdb-2.5.1.dfsg/lib/util/0000755000175000017500000000000012245023514014750 5ustar mathieumathieuctdb-2.5.1.dfsg/lib/util/util.h0000644000175000017500000004207412245023514016105 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Utility functions for Samba Copyright (C) Andrew Tridgell 1992-1999 Copyright (C) Jelmer Vernooij 2005 This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #ifndef _SAMBA_UTIL_H_ #define _SAMBA_UTIL_H_ /** * @file * @brief Helpful macros */ struct smbsrv_tcon; #ifdef _SAMBA_BUILD_ extern const char *logfile; #endif extern const char *panic_action; extern void (*pre_panic_action_hook)(void); extern void (*post_panic_action_hook)(void); /** * assert macros */ #ifdef DEVELOPER #define SMB_ASSERT(b) do { if (!(b)) { \ DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \ __FILE__, __LINE__, #b)); smb_panic("assert failed: " #b); }} while(0) #else /* redefine the assert macro for non-developer builds */ #define SMB_ASSERT(b) do { if (!(b)) { \ DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \ __FILE__, __LINE__, #b)); }} while (0) #endif #if _SAMBA_BUILD_ == 4 #ifdef VALGRIND #define strlen(x) valgrind_strlen(x) size_t valgrind_strlen(const char *s); #endif #endif #ifndef ABS #define ABS(a) ((a)>0?(a):(-(a))) #endif /** * Write backtrace to debug log */ _PUBLIC_ void call_backtrace(void); /** Something really nasty happened - panic ! **/ _PUBLIC_ _NORETURN_ void smb_panic(const char *why); /** setup our fault handlers **/ _PUBLIC_ void fault_setup(const char *pname); /** register a fault handler. Should only be called once in the execution of smbd. */ _PUBLIC_ bool register_fault_handler(const char *name, void (*fault_handler)(int sig)); /* The following definitions come from lib/util/signal.c */ /** Block sigs. **/ void BlockSignals(bool block, int signum); /** Catch a signal. This should implement the following semantics: 1) The handler remains installed after being called. 2) The signal should be blocked during handler execution. **/ void (*CatchSignal(int signum,void (*handler)(int )))(int); /** Ignore SIGCLD via whatever means is necessary for this OS. **/ void CatchChild(void); /** Catch SIGCLD but leave the child around so it's status can be reaped. **/ void CatchChildLeaveStatus(void); /* The following definitions come from lib/util/util_str.c */ /** Trim the specified elements off the front and back of a string. **/ _PUBLIC_ bool trim_string(char *s, const char *front, const char *back); /** Find the number of 'c' chars in a string **/ _PUBLIC_ _PURE_ size_t count_chars(const char *s, char c); /** Safe string copy into a known length string. maxlength does not include the terminating zero. **/ _PUBLIC_ char *safe_strcpy(char *dest,const char *src, size_t maxlength); /** Safe string cat into a string. maxlength does not include the terminating zero. **/ _PUBLIC_ char *safe_strcat(char *dest, const char *src, size_t maxlength); /** Routine to get hex characters and turn them into a 16 byte array. the array can be variable length, and any non-hex-numeric characters are skipped. "0xnn" or "0Xnn" is specially catered for. valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n" **/ _PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len); #ifdef _SAMBA_BUILD_ /** * Parse a hex string and return a data blob. */ _PUBLIC_ _PURE_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) ; #endif /** * Routine to print a buffer as HEX digits, into an allocated string. */ _PUBLIC_ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer); /** * talloc version of hex_encode() */ _PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len); /** Substitute a string for a pattern in another string. Make sure there is enough room! This routine looks for pattern in s and replaces it with insert. It may do multiple replacements. Any of " ; ' $ or ` in the insert string are replaced with _ if len==0 then the string cannot be extended. This is different from the old use of len==0 which was for no length checks to be done. **/ _PUBLIC_ void string_sub(char *s,const char *pattern, const char *insert, size_t len); _PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s, const char *pattern, const char *insert); /** Similar to string_sub() but allows for any character to be substituted. Use with caution! if len==0 then the string cannot be extended. This is different from the old use of len==0 which was for no length checks to be done. **/ _PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len); /** Unescape a URL encoded string, in place. **/ _PUBLIC_ void rfc1738_unescape(char *buf); /** format a string into length-prefixed dotted domain format, as used in NBT and in some ADS structures **/ _PUBLIC_ const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s); /** * Add a string to an array of strings. * * num should be a pointer to an integer that holds the current * number of elements in strings. It will be updated by this function. */ _PUBLIC_ bool add_string_to_array(TALLOC_CTX *mem_ctx, const char *str, const char ***strings, int *num); /** varient of strcmp() that handles NULL ptrs **/ _PUBLIC_ int strcmp_safe(const char *s1, const char *s2); /** return the number of bytes occupied by a buffer in ASCII format the result includes the null termination limited by 'n' bytes **/ _PUBLIC_ size_t ascii_len_n(const char *src, size_t n); /** Set a boolean variable from the text value stored in the passed string. Returns true in success, false if the passed string does not correctly represent a boolean. **/ _PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean); /** * Parse a string containing a boolean value. * * val will be set to the read value. * * @retval true if a boolean value was parsed, false otherwise. */ _PUBLIC_ bool conv_str_bool(const char * str, bool * val); #if _SAMBA_BUILD_ == 4 /** * Convert a size specification like 16K into an integral number of bytes. **/ _PUBLIC_ bool conv_str_size(const char * str, uint64_t * val); #endif /** * Parse a uint64_t value from a string * * val will be set to the value read. * * @retval true if parsing was successful, false otherwise */ _PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val); /** return the number of bytes occupied by a buffer in CH_UTF16 format the result includes the null termination **/ _PUBLIC_ size_t utf16_len(const void *buf); /** return the number of bytes occupied by a buffer in CH_UTF16 format the result includes the null termination limited by 'n' bytes **/ _PUBLIC_ size_t utf16_len_n(const void *src, size_t n); _PUBLIC_ size_t ucs2_align(const void *base_ptr, const void *p, int flags); /** Do a case-insensitive, whitespace-ignoring string compare. **/ _PUBLIC_ int strwicmp(const char *psz1, const char *psz2); /** String replace. **/ _PUBLIC_ void string_replace(char *s, char oldc, char newc); /** * Compare 2 strings. * * @note The comparison is case-insensitive. **/ _PUBLIC_ bool strequal(const char *s1, const char *s2); /* The following definitions come from lib/util/util_strlist.c */ #ifdef _SAMBA_BUILD_ /* separators for lists */ #ifndef LIST_SEP #define LIST_SEP " \t,\n\r" #endif /** build a null terminated list of strings from a input string and a separator list. The separator list must contain characters less than or equal to 0x2f for this to work correctly on multi-byte strings */ _PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep); /** * build a null terminated list of strings from an argv-like input string * Entries are seperated by spaces and can be enclosed by quotes. * Does NOT support escaping */ _PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep); /** * join a list back to one string */ _PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator); /** join a list back to one (shell-like) string; entries * seperated by spaces, using quotes where necessary */ _PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep); /** return the number of elements in a string list */ _PUBLIC_ size_t str_list_length(const char * const *list); /** copy a string list */ _PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list); /** Return true if all the elements of the list match exactly. */ _PUBLIC_ bool str_list_equal(const char **list1, const char **list2); /** add an entry to a string list */ _PUBLIC_ const char **str_list_add(const char **list, const char *s); /** remove an entry from a string list */ _PUBLIC_ void str_list_remove(const char **list, const char *s); /** return true if a string is in a list */ _PUBLIC_ bool str_list_check(const char **list, const char *s); /** return true if a string is in a list, case insensitively */ _PUBLIC_ bool str_list_check_ci(const char **list, const char *s); #endif /* The following definitions come from lib/util/util_file.c */ #ifdef _SAMBA_BUILD_ /** read a line from a file with possible \ continuation chars. Blanks at the start or end of a line are stripped. The string will be allocated if s2 is NULL **/ _PUBLIC_ char *fgets_slash(char *s2,int maxlen,XFILE *f); #endif /** * Read one line (data until next newline or eof) and allocate it */ _PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint); #ifdef _SAMBA_BUILD_ /** load a file into memory from a fd. **/ _PUBLIC_ char *fd_load(int fd, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx); char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx); /** load a file into memory **/ _PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx); #endif /** mmap (if possible) or read a file **/ _PUBLIC_ void *map_file(const char *fname, size_t size); #ifdef _SAMBA_BUILD_ /** load a file into memory and return an array of pointers to lines in the file must be freed with talloc_free(). **/ _PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx); #endif /** load a fd into memory and return an array of pointers to lines in the file must be freed with talloc_free(). If convert is true calls unix_to_dos on the list. **/ _PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx); /** take a list of lines and modify them to produce a list where \ continues a line **/ _PUBLIC_ void file_lines_slashcont(char **lines); /** save a lump of data into a file. Mostly used for debugging */ _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length); _PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0); _PUBLIC_ int fdprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3); _PUBLIC_ bool large_file_support(const char *path); /* The following definitions come from lib/util/util.c */ /** Find a suitable temporary directory. The result should be copied immediately as it may be overwritten by a subsequent call. **/ _PUBLIC_ const char *tmpdir(void); /** Check if a file exists - call vfs_file_exist for samba files. **/ _PUBLIC_ bool file_exist(const char *fname); /** Check a files mod time. **/ _PUBLIC_ time_t file_modtime(const char *fname); /** Check if a directory exists. **/ _PUBLIC_ bool directory_exist(const char *dname); /** * Try to create the specified directory if it didn't exist. * * @retval true if the directory already existed and has the right permissions * or was successfully created. */ _PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid, mode_t dir_perms); /** Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, else if SYSV use O_NDELAY if BSD use FNDELAY **/ _PUBLIC_ int set_blocking(int fd, bool set); /** Sleep for a specified number of milliseconds. **/ _PUBLIC_ void msleep(unsigned int t); /** Get my own name, return in malloc'ed storage. **/ _PUBLIC_ char* get_myname(void); /** Return true if a string could be a pure IP address. **/ _PUBLIC_ bool is_ipaddress(const char *str); /** Interpret an internet address or name into an IP address in 4 byte form. **/ _PUBLIC_ uint32_t interpret_addr(const char *str); /** A convenient addition to interpret_addr(). **/ _PUBLIC_ struct in_addr interpret_addr2(const char *str); /** Check if an IP is the 0.0.0.0. **/ _PUBLIC_ bool is_zero_ip_v4(struct in_addr ip); /** Are two IPs on the same subnet? **/ _PUBLIC_ bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr mask); _PUBLIC_ bool is_ipaddress_v4(const char *str); /** Check if a process exists. Does this work on all unixes? **/ _PUBLIC_ bool process_exists_by_pid(pid_t pid); /** Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping is dealt with in posix.c **/ _PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type); /** malloc that aborts with smb_panic on fail or zero size. **/ _PUBLIC_ void *smb_xmalloc(size_t size); /** Memdup with smb_panic on fail. **/ _PUBLIC_ void *smb_xmemdup(const void *p, size_t size); /** strdup that aborts on malloc fail. **/ _PUBLIC_ char *smb_xstrdup(const char *s); char *smb_xstrndup(const char *s, size_t n); /** Like strdup but for memory. **/ _PUBLIC_ void *memdup(const void *p, size_t size); /** * see if a range of memory is all zero. A NULL pointer is considered * to be all zero */ _PUBLIC_ bool all_zero(const uint8_t *ptr, size_t size); /** realloc an array, checking for integer overflow in the array size */ _PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count, bool free_on_fail); void *malloc_array(size_t el_size, unsigned int count); /* The following definitions come from lib/util/fsusage.c */ /** * Retrieve amount of free disk space. * this does all of the system specific guff to get the free disk space. * It is derived from code in the GNU fileutils package, but has been * considerably mangled for use here * * results are returned in *dfree and *dsize, in 512 byte units */ _PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize); /* The following definitions come from lib/util/ms_fnmatch.c */ /** * @file * @brief MS-style Filename matching */ #if _SAMBA_BUILD_ == 4 /* protocol types. It assumes that higher protocols include lower protocols as subsets. FIXME: Move to one of the smb-specific headers */ enum protocol_types { PROTOCOL_NONE, PROTOCOL_CORE, PROTOCOL_COREPLUS, PROTOCOL_LANMAN1, PROTOCOL_LANMAN2, PROTOCOL_NT1, PROTOCOL_SMB2 }; int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol); /** a generic fnmatch function - uses for non-CIFS pattern matching */ int gen_fnmatch(const char *pattern, const char *string); #endif /* The following definitions come from lib/util/mutex.c */ #ifdef _SAMBA_BUILD_ /** register a set of mutex/rwlock handlers. Should only be called once in the execution of smbd. */ _PUBLIC_ bool register_mutex_handlers(const char *name, struct mutex_ops *ops); #endif /* The following definitions come from lib/util/idtree.c */ /** initialise a idr tree. The context return value must be passed to all subsequent idr calls. To destroy the idr tree use talloc_free() on this context */ _PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx); /** allocate the next available id, and assign 'ptr' into its slot. you can retrieve later this pointer using idr_find() */ _PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit); /** allocate a new id, giving the first available value greater than or equal to the given starting id */ _PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit); /** allocate a new id randomly in the given range */ _PUBLIC_ int idr_get_new_random(struct idr_context *idp, void *ptr, int limit); /** find a pointer value previously set with idr_get_new given an id */ _PUBLIC_ void *idr_find(struct idr_context *idp, int id); /** remove an id from the idr tree */ _PUBLIC_ int idr_remove(struct idr_context *idp, int id); /* The following definitions come from lib/util/become_daemon.c */ #if _SAMBA_BUILD_ == 4 /** Become a daemon, discarding the controlling terminal. **/ _PUBLIC_ void become_daemon(bool fork); #endif /** * Load a ini-style file. */ bool pm_process( const char *fileName, bool (*sfunc)(const char *, void *), bool (*pfunc)(const char *, const char *, void *), void *userdata); bool unmap_file(void *start, size_t size); #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr))) #endif /* _SAMBA_UTIL_H_ */ ctdb-2.5.1.dfsg/lib/util/fault.m40000644000175000017500000000074312245023514016331 0ustar mathieumathieuAC_CHECK_HEADERS(execinfo.h) AC_SEARCH_LIBS_EXT(backtrace, [execinfo], EXECINFO_LIBS) AC_CHECK_FUNC_EXT(backtrace, $EXECINFO_LIBS) if test x"$ac_cv_header_execinfo_h" = x"yes" -a x"$ac_cv_func_ext_backtrace" = x"yes";then SMB_ENABLE(EXECINFO, YES) EXECINFO_CFLAGS="$CFLAGS" EXECINFO_CPPFLAGS="$CPPFLAGS" EXECINFO_LDFLAGS="$LDFLAGS" else SMB_ENABLE(EXECINFO,NO) fi SMB_EXT_LIB(EXECINFO, [${EXECINFO_LIBS}], [${EXECINFO_CFLAGS}], [${EXECINFO_CPPFLAGS}], [${EXECINFO_LDFLAGS}]) ctdb-2.5.1.dfsg/lib/util/signal.m40000644000175000017500000000005712245023514016471 0ustar mathieumathieuAC_CHECK_FUNCS(sigprocmask sigblock sigaction) ctdb-2.5.1.dfsg/lib/util/dlinklist.h0000644000175000017500000001116712245023514017124 0ustar mathieumathieu/* Unix SMB/CIFS implementation. some simple double linked list macros Copyright (C) Andrew Tridgell 1998-2010 This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ /* To use these macros you must have a structure containing a next and prev pointer */ #ifndef _DLINKLIST_H #define _DLINKLIST_H /* February 2010 - changed list format to have a prev pointer from the list head. This makes DLIST_ADD_END() O(1) even though we only have one list pointer. The scheme is as follows: 1) with no entries in the list: list_head == NULL 2) with 1 entry in the list: list_head->next == NULL list_head->prev == list_head 3) with 2 entries in the list: list_head->next == element2 list_head->prev == element2 element2->prev == list_head element2->next == NULL 4) with N entries in the list: list_head->next == element2 list_head->prev == elementN elementN->prev == element{N-1} elementN->next == NULL This allows us to find the tail of the list by using list_head->prev, which means we can add to the end of the list in O(1) time Note that the 'type' arguments below are no longer needed, but are kept for now to prevent an incompatible argument change */ /* add an element at the front of a list */ #define DLIST_ADD(list, p) \ do { \ if (!(list)) { \ (p)->prev = (list) = (p); \ (p)->next = NULL; \ } else { \ (p)->prev = (list)->prev; \ (list)->prev = (p); \ (p)->next = (list); \ (list) = (p); \ } \ } while (0) /* remove an element from a list Note that the element doesn't have to be in the list. If it isn't then this is a no-op */ #define DLIST_REMOVE(list, p) \ do { \ if ((p) == (list)) { \ if ((p)->next) (p)->next->prev = (p)->prev; \ (list) = (p)->next; \ } else if ((list) && (p) == (list)->prev) { \ (p)->prev->next = NULL; \ (list)->prev = (p)->prev; \ } else { \ if ((p)->prev) (p)->prev->next = (p)->next; \ if ((p)->next) (p)->next->prev = (p)->prev; \ } \ if ((p) != (list)) (p)->next = (p)->prev = NULL; \ } while (0) /* find the head of the list given any element in it. Note that this costs O(N), so you should avoid this macro if at all possible! */ #define DLIST_HEAD(p, result_head) \ do { \ (result_head) = (p); \ while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \ } while(0) /* return the last element in the list */ #define DLIST_TAIL(list) ((list)?(list)->prev:NULL) /* return the previous element in the list. */ #define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL) /* insert 'p' after the given element 'el' in a list. If el is NULL then this is the same as a DLIST_ADD() */ #define DLIST_ADD_AFTER(list, p, el) \ do { \ if (!(list) || !(el)) { \ DLIST_ADD(list, p); \ } else { \ (p)->prev = (el); \ (p)->next = (el)->next; \ (el)->next = (p); \ if ((p)->next) (p)->next->prev = (p); \ if ((list)->prev == (el)) (list)->prev = (p); \ }\ } while (0) /* add to the end of a list. Note that 'type' is ignored */ #define DLIST_ADD_END(list, p, type) \ do { \ if (!(list)) { \ DLIST_ADD(list, p); \ } else { \ DLIST_ADD_AFTER(list, p, (list)->prev); \ } \ } while (0) /* promote an element to the from of a list */ #define DLIST_PROMOTE(list, p) \ do { \ DLIST_REMOVE(list, p); \ DLIST_ADD(list, p); \ } while (0) /* demote an element to the end of a list. Note that 'type' is ignored */ #define DLIST_DEMOTE(list, p, type) \ do { \ DLIST_REMOVE(list, p); \ DLIST_ADD_END(list, p, NULL); \ } while (0) /* concatenate two lists - putting all elements of the 2nd list at the end of the first list. Note that 'type' is ignored */ #define DLIST_CONCATENATE(list1, list2, type) \ do { \ if (!(list1)) { \ (list1) = (list2); \ } else { \ (list1)->prev->next = (list2); \ if (list2) { \ void *_tmplist = (void *)(list1)->prev; \ (list1)->prev = (list2)->prev; \ (list2)->prev = _tmplist; \ } \ } \ } while (0) #endif /* _DLINKLIST_H */ ctdb-2.5.1.dfsg/lib/util/debug.h0000644000175000017500000000211612245023514016207 0ustar mathieumathieu/* Unix SMB/CIFS implementation. ctdb debug functions Copyright (C) Volker Lendecke 2007 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ void (*do_debug_v)(const char *, va_list ap); const char *debug_extra; void (*do_debug_add_v)(const char *, va_list ap); void log_ringbuffer(const char *format, ...); void do_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); void do_debug_add(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); void dump_data(int level, const uint8_t *buf1, size_t len); ctdb-2.5.1.dfsg/lib/util/db_wrap.c0000644000175000017500000000501412245023514016532 0ustar mathieumathieu/* Unix SMB/CIFS implementation. database wrap functions Copyright (C) Andrew Tridgell 2004 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ /* the stupidity of the unix fcntl locking design forces us to never allow a database file to be opened twice in the same process. These wrappers provide convenient access to a tdb or ldb, taking advantage of talloc destructors to ensure that only a single open is done */ #include "includes.h" #include "lib/util/dlinklist.h" #include "tdb.h" #include "db_wrap.h" static struct tdb_wrap *tdb_list; /* destroy the last connection to a tdb */ static int tdb_wrap_destructor(struct tdb_wrap *w) { tdb_close(w->tdb); DLIST_REMOVE(tdb_list, w); return 0; } static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) { if (level <= TDB_DEBUG_ERROR) { va_list ap; this_log_level = level; char newfmt[strlen(tdb_name(tdb)) + 1 + strlen(fmt) + 1]; sprintf(newfmt, "%s:%s", tdb_name(tdb), fmt); va_start(ap, fmt); do_debug_v(newfmt, ap); va_end(ap); } } /* wrapped connection to a tdb database to close just talloc_free() the tdb_wrap pointer */ struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx, const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode) { struct tdb_wrap *w; struct tdb_logging_context log_ctx; log_ctx.log_fn = log_fn; log_ctx.log_private = NULL; for (w=tdb_list;w;w=w->next) { if (strcmp(name, w->name) == 0) { return talloc_reference(mem_ctx, w); } } w = talloc(mem_ctx, struct tdb_wrap); if (w == NULL) { return NULL; } w->name = talloc_strdup(w, name); if (w->name == NULL) { talloc_free(w); return NULL; } w->tdb = tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, &log_ctx, NULL); if (w->tdb == NULL) { talloc_free(w); return NULL; } talloc_set_destructor(w, tdb_wrap_destructor); DLIST_ADD(tdb_list, w); return w; } ctdb-2.5.1.dfsg/lib/util/fault.c0000644000175000017500000001325312245023514016233 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Critical Fault handling Copyright (C) Andrew Tridgell 1992-1998 This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #include "includes.h" #include "system/wait.h" #include "system/filesys.h" /** * @file * @brief Fault handling */ /* the registered fault handler */ static struct { const char *name; void (*fault_handler)(int sig); } fault_handlers; static const char *progname; #ifdef HAVE_BACKTRACE #include #elif HAVE_LIBEXC_H #include #endif /** * Write backtrace to debug log */ _PUBLIC_ void call_backtrace(void) { #ifdef HAVE_BACKTRACE #ifndef BACKTRACE_STACK_SIZE #define BACKTRACE_STACK_SIZE 64 #endif void *backtrace_stack[BACKTRACE_STACK_SIZE]; size_t backtrace_size; char **backtrace_strings; /* get the backtrace (stack frames) */ backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE); backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size); DEBUG(0, ("BACKTRACE: %lu stack frames:\n", (unsigned long)backtrace_size)); if (backtrace_strings) { int i; for (i = 0; i < backtrace_size; i++) DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i])); /* Leak the backtrace_strings, rather than risk what free() might do */ } #elif HAVE_LIBEXC #define NAMESIZE 32 /* Arbitrary */ #ifndef BACKTRACE_STACK_SIZE #define BACKTRACE_STACK_SIZE 64 #endif /* The IRIX libexc library provides an API for unwinding the stack. See * libexc(3) for details. Apparantly trace_back_stack leaks memory, but * since we are about to abort anyway, it hardly matters. * * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this * will fail with a nasty message upon failing to open the /proc entry. */ { uint64_t addrs[BACKTRACE_STACK_SIZE]; char * names[BACKTRACE_STACK_SIZE]; char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE]; int i; int levels; ZERO_ARRAY(addrs); ZERO_ARRAY(names); ZERO_ARRAY(namebuf); for (i = 0; i < BACKTRACE_STACK_SIZE; i++) { names[i] = namebuf + (i * NAMESIZE); } levels = trace_back_stack(0, addrs, names, BACKTRACE_STACK_SIZE, NAMESIZE); DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels)); for (i = 0; i < levels; i++) { DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i])); } } #undef NAMESIZE #else DEBUG(0, ("call_backtrace: not implemented\n")); #endif } _PUBLIC_ const char *panic_action = NULL; _PUBLIC_ void (*pre_panic_action_hook)(void) = NULL; _PUBLIC_ void (*post_panic_action_hook)(void) = NULL; /** Something really nasty happened - panic ! **/ _PUBLIC_ void smb_panic(const char *why) { int result; if (panic_action && *panic_action) { char pidstr[20]; char cmdstring[200]; strlcpy(cmdstring, panic_action, sizeof(cmdstring)); snprintf(pidstr, sizeof(pidstr), "%u", getpid()); all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring)); if (progname) { all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring)); } DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring)); if (pre_panic_action_hook) { pre_panic_action_hook(); } result = system(cmdstring); if (post_panic_action_hook) { post_panic_action_hook(); } if (result == -1) DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n", strerror(errno))); else DEBUG(0, ("smb_panic(): action returned status %d\n", WEXITSTATUS(result))); } DEBUG(0,("PANIC: %s\n", why)); call_backtrace(); #ifdef SIGABRT CatchSignal(SIGABRT, SIG_DFL); #endif abort(); } /** report a fault **/ _NORETURN_ static void fault_report(int sig) { static int counter; if (counter) _exit(1); DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n")); DEBUG(0,("INTERNAL ERROR: Signal %d in %s pid %d",sig, progname, (int)getpid())); DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n")); DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n")); smb_panic("internal error"); exit(1); } /** catch serious errors **/ _NORETURN_ static void sig_fault(int sig) { if (fault_handlers.fault_handler) { /* we have a fault handler, call it. It may not return. */ fault_handlers.fault_handler(sig); } /* If it returns or doesn't exist, use regular reporter */ fault_report(sig); } /** setup our fault handlers **/ _PUBLIC_ void fault_setup(const char *pname) { if (progname == NULL) { progname = pname; } #ifdef SIGSEGV CatchSignal(SIGSEGV, sig_fault); #endif #ifdef SIGBUS CatchSignal(SIGBUS, sig_fault); #endif #ifdef SIGABRT CatchSignal(SIGABRT, sig_fault); #endif #ifdef SIGFPE CatchSignal(SIGFPE, sig_fault); #endif } /** register a fault handler. Should only be called once in the execution of smbd. */ _PUBLIC_ bool register_fault_handler(const char *name, void (*fault_handler)(int sig)) { if (fault_handlers.name != NULL) { /* it's already registered! */ DEBUG(2,("fault handler '%s' already registered - failed '%s'\n", fault_handlers.name, name)); return false; } fault_handlers.name = name; fault_handlers.fault_handler = fault_handler; DEBUG(2,("fault handler '%s' registered\n", name)); return true; } ctdb-2.5.1.dfsg/lib/util/util.c0000644000175000017500000000251012245023514016067 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Copyright (C) Andrew Tridgell 2005 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #include "includes.h" #include "system/filesys.h" /** Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, else if SYSV use O_NDELAY if BSD use FNDELAY **/ _PUBLIC_ int set_blocking(int fd, bool set) { int val; #ifdef O_NONBLOCK #define FLAG_TO_SET O_NONBLOCK #else #ifdef SYSV #define FLAG_TO_SET O_NDELAY #else /* BSD */ #define FLAG_TO_SET FNDELAY #endif #endif if((val = fcntl(fd, F_GETFL, 0)) == -1) return -1; if(set) /* Turn blocking on - ie. clear nonblock flag */ val &= ~FLAG_TO_SET; else val |= FLAG_TO_SET; return fcntl( fd, F_SETFL, val); #undef FLAG_TO_SET } ctdb-2.5.1.dfsg/lib/util/strlist.c0000644000175000017500000000253612245023514016626 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Copyright (C) Andrew Tridgell 2005 Copyright (C) Jelmer Vernooij 2005 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #include "includes.h" #include "system/locale.h" /** return the number of elements in a string list */ _PUBLIC_ size_t str_list_length(const char **list) { size_t ret; for (ret=0;list && list[ret];ret++) /* noop */ ; return ret; } /** add an entry to a string list */ _PUBLIC_ const char **str_list_add(const char **list, const char *s) { size_t len = str_list_length(list); const char **ret; ret = talloc_realloc(NULL, list, const char *, len+2); if (ret == NULL) return NULL; ret[len] = talloc_strdup(ret, s); if (ret[len] == NULL) return NULL; ret[len+1] = NULL; return ret; } ctdb-2.5.1.dfsg/lib/util/db_wrap.h0000644000175000017500000000205612245023514016542 0ustar mathieumathieu/* Unix SMB/CIFS implementation. database wrap headers Copyright (C) Andrew Tridgell 2004 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #ifndef _DB_WRAP_H #define _DB_WRAP_H struct tdb_wrap { struct tdb_context *tdb; const char *name; struct tdb_wrap *next, *prev; }; struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx, const char *name, int hash_size, int tdb_flags, int open_flags, mode_t mode); #endif /* _DB_WRAP_H */ ctdb-2.5.1.dfsg/lib/util/debug.c0000644000175000017500000000624312245023514016207 0ustar mathieumathieu/* Unix SMB/CIFS implementation. ctdb debug functions Copyright (C) Volker Lendecke 2007 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #include "includes.h" #include "system/time.h" #include #include static void _do_debug_v(const char *format, va_list ap) { struct timeval t; char *s = NULL; struct tm *tm; char tbuf[100]; int ret; ret = vasprintf(&s, format, ap); if (ret == -1) { fprintf(stderr, "vasprintf failed in _do_debug_v, cannot print debug message.\n"); fflush(stderr); return; } t = timeval_current(); tm = localtime(&t.tv_sec); strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm); fprintf(stderr, "%s.%06u [%s%5u]: %s", tbuf, (unsigned)t.tv_usec, debug_extra, (unsigned)getpid(), s); fflush(stderr); free(s); } /* default logging function */ void (*do_debug_v)(const char *, va_list ap) = _do_debug_v; const char *debug_extra = ""; void do_debug(const char *format, ...) { va_list ap; va_start(ap, format); do_debug_v(format, ap); va_end(ap); } static void _do_debug_add_v(const char *format, va_list ap) { char *s = NULL; int ret; ret = vasprintf(&s, format, ap); if (ret == -1) { fprintf(stderr, "vasprintf failed in _do_debug_add_v, cannot print debug message.\n"); fflush(stderr); return; } fprintf(stderr, "%s", s); fflush(stderr); free(s); } /* default logging function */ void (*do_debug_add_v)(const char *, va_list ap) = _do_debug_add_v; void do_debug_add(const char *format, ...) { va_list ap; va_start(ap, format); do_debug_add_v(format, ap); va_end(ap); } static void print_asc(int level, const uint8_t *buf, size_t len) { int i; for (i=0;i8) DEBUGADD(level,(" ")); while (n--) DEBUGADD(level,(" ")); n = MIN(8,i%16); print_asc(level,&buf[i-(i%16)],n); DEBUGADD(level,( " " )); n = (i%16) - n; if (n>0) print_asc(level,&buf[i-n],n); DEBUGADD(level,("\n")); } DEBUG(level, (__location__ " dump data of size %i finished\n", (int)len)); } ctdb-2.5.1.dfsg/lib/util/util_file.c0000644000175000017500000000456012245023514017075 0ustar mathieumathieu/* functions taken from samba4 for quick prototyping of ctdb. These are not intended to remain part of ctdb */ #include "includes.h" #include "system/filesys.h" static char *fd_load(int fd, size_t *size, TALLOC_CTX *mem_ctx) { struct stat sbuf; char *p; if (fstat(fd, &sbuf) != 0) return NULL; p = (char *)talloc_size(mem_ctx, sbuf.st_size+1); if (!p) return NULL; if (read(fd, p, sbuf.st_size) != sbuf.st_size) { talloc_free(p); return NULL; } p[sbuf.st_size] = 0; if (size) *size = sbuf.st_size; return p; } static char *file_load(const char *fname, size_t *size, TALLOC_CTX *mem_ctx) { int fd; char *p; if (!fname || !*fname) return NULL; fd = open(fname,O_RDONLY); if (fd == -1) return NULL; p = fd_load(fd, size, mem_ctx); close(fd); return p; } /** parse a buffer into lines 'p' will be freed on error, and otherwise will be made a child of the returned array **/ static char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx) { int i; char *s, **ret; if (!p) return NULL; for (s = p, i=0; s < p+size; s++) { if (s[0] == '\n') i++; } ret = talloc_array(mem_ctx, char *, i+2); if (!ret) { talloc_free(p); return NULL; } talloc_steal(ret, p); memset(ret, 0, sizeof(ret[0])*(i+2)); if (numlines) *numlines = i; ret[0] = p; for (s = p, i=0; s < p+size; s++) { if (s[0] == '\n') { s[0] = 0; i++; ret[i] = s+1; } if (s[0] == '\r') s[0] = 0; } return ret; } /** load a file into memory and return an array of pointers to lines in the file must be freed with talloc_free(). **/ _PUBLIC_ char **file_lines_load(const char *fname, int *numlines, TALLOC_CTX *mem_ctx) { char *p; size_t size; p = file_load(fname, &size, mem_ctx); if (!p) return NULL; return file_lines_parse(p, size, numlines, mem_ctx); } char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len) { int i; char *hex_buffer; hex_buffer = talloc_array(mem_ctx, char, (len*2)+1); for (i = 0; i < len; i++) slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]); return hex_buffer; } uint8_t *hex_decode_talloc(TALLOC_CTX *mem_ctx, const char *hex_in, size_t *len) { int i, num; uint8_t *buffer; *len = strlen(hex_in) / 2; buffer = talloc_array(mem_ctx, unsigned char, *len); for (i=0; i<*len; i++) { sscanf(&hex_in[i*2], "%02X", &num); buffer[i] = (uint8_t)num; } return buffer; } ctdb-2.5.1.dfsg/lib/util/signal.c0000644000175000017500000000675112245023514016402 0ustar mathieumathieu/* Unix SMB/CIFS implementation. signal handling functions Copyright (C) Andrew Tridgell 1998 This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #include "includes.h" #include "system/wait.h" /** * @file * @brief Signal handling */ /**************************************************************************** Catch child exits and reap the child zombie status. ****************************************************************************/ static void sig_cld(int signum) { while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0) ; /* * Turns out it's *really* important not to * restore the signal handler here if we have real POSIX * signal handling. If we do, then we get the signal re-delivered * immediately - hey presto - instant loop ! JRA. */ #if !defined(HAVE_SIGACTION) CatchSignal(SIGCLD, sig_cld); #endif } /**************************************************************************** catch child exits - leave status; ****************************************************************************/ static void sig_cld_leave_status(int signum) { /* * Turns out it's *really* important not to * restore the signal handler here if we have real POSIX * signal handling. If we do, then we get the signal re-delivered * immediately - hey presto - instant loop ! JRA. */ #if !defined(HAVE_SIGACTION) CatchSignal(SIGCLD, sig_cld_leave_status); #endif } /** Block sigs. **/ void BlockSignals(bool block, int signum) { #ifdef HAVE_SIGPROCMASK sigset_t set; sigemptyset(&set); sigaddset(&set,signum); sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL); #elif defined(HAVE_SIGBLOCK) if (block) { sigblock(sigmask(signum)); } else { sigsetmask(siggetmask() & ~sigmask(signum)); } #else /* yikes! This platform can't block signals? */ static int done; if (!done) { DEBUG(0,("WARNING: No signal blocking available\n")); done=1; } #endif } /** Catch a signal. This should implement the following semantics: 1) The handler remains installed after being called. 2) The signal should be blocked during handler execution. **/ void (*CatchSignal(int signum,void (*handler)(int )))(int) { #ifdef HAVE_SIGACTION struct sigaction act; struct sigaction oldact; ZERO_STRUCT(act); act.sa_handler = handler; #ifdef SA_RESTART /* * We *want* SIGALRM to interrupt a system call. */ if(signum != SIGALRM) act.sa_flags = SA_RESTART; #endif sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask,signum); sigaction(signum,&act,&oldact); return oldact.sa_handler; #else /* !HAVE_SIGACTION */ /* FIXME: need to handle sigvec and systems with broken signal() */ return signal(signum, handler); #endif } /** Ignore SIGCLD via whatever means is necessary for this OS. **/ void CatchChild(void) { CatchSignal(SIGCLD, sig_cld); } /** Catch SIGCLD but leave the child around so it's status can be reaped. **/ void CatchChildLeaveStatus(void) { CatchSignal(SIGCLD, sig_cld_leave_status); } ctdb-2.5.1.dfsg/lib/util/idtree.c0000644000175000017500000002117412245023514016375 0ustar mathieumathieu/* Unix SMB/CIFS implementation. very efficient functions to manage mapping a id (such as a fnum) to a pointer. This is used for fnum and search id allocation. Copyright (C) Andrew Tridgell 2004 This code is derived from lib/idr.c in the 2.6 Linux kernel, which was written by Jim Houston jim.houston@ccur.com, and is Copyright (C) 2002 by Concurrent Computer Corporation This program 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 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ /* see the section marked "public interface" below for documentation */ /** * @file */ #include "includes.h" #define IDR_BITS 5 #define IDR_FULL 0xfffffffful #if 0 /* unused */ #define TOP_LEVEL_FULL (IDR_FULL >> 30) #endif #define IDR_SIZE (1 << IDR_BITS) #define IDR_MASK ((1 << IDR_BITS)-1) #define MAX_ID_SHIFT (sizeof(int)*8 - 1) #define MAX_ID_BIT (1U << MAX_ID_SHIFT) #define MAX_ID_MASK (MAX_ID_BIT - 1) #define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS #define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL #define set_bit(bit, v) (v) |= (1<<(bit)) #define clear_bit(bit, v) (v) &= ~(1<<(bit)) #define test_bit(bit, v) ((v) & (1<<(bit))) struct idr_layer { uint32_t bitmap; struct idr_layer *ary[IDR_SIZE]; int count; }; struct idr_context { struct idr_layer *top; struct idr_layer *id_free; int layers; int id_free_cnt; }; static struct idr_layer *alloc_layer(struct idr_context *idp) { struct idr_layer *p; if (!(p = idp->id_free)) return NULL; idp->id_free = p->ary[0]; idp->id_free_cnt--; p->ary[0] = NULL; return p; } static int find_next_bit(uint32_t bm, int maxid, int n) { while (nary[0] = idp->id_free; idp->id_free = p; idp->id_free_cnt++; } static int idr_pre_get(struct idr_context *idp) { while (idp->id_free_cnt < IDR_FREE_MAX) { struct idr_layer *new = talloc_zero(idp, struct idr_layer); if(new == NULL) return (0); free_layer(idp, new); } return 1; } static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id) { int n, m, sh; struct idr_layer *p, *new; struct idr_layer *pa[MAX_LEVEL+1]; unsigned int l, id, oid; uint32_t bm; memset(pa, 0, sizeof(pa)); id = *starting_id; restart: p = idp->top; l = idp->layers; pa[l--] = NULL; while (1) { /* * We run around this while until we reach the leaf node... */ n = (id >> (IDR_BITS*l)) & IDR_MASK; bm = ~p->bitmap; m = find_next_bit(bm, IDR_SIZE, n); if (m == IDR_SIZE) { /* no space available go back to previous layer. */ l++; oid = id; id = (id | ((1 << (IDR_BITS*l))-1)) + 1; /* if already at the top layer, we need to grow */ if (!(p = pa[l])) { *starting_id = id; return -2; } /* If we need to go up one layer, continue the * loop; otherwise, restart from the top. */ sh = IDR_BITS * (l + 1); if (oid >> sh == id >> sh) continue; else goto restart; } if (m != n) { sh = IDR_BITS*l; id = ((id >> sh) ^ n ^ m) << sh; } if ((id >= MAX_ID_BIT) || (id < 0)) return -1; if (l == 0) break; /* * Create the layer below if it is missing. */ if (!p->ary[m]) { if (!(new = alloc_layer(idp))) return -1; p->ary[m] = new; p->count++; } pa[l--] = p; p = p->ary[m]; } /* * We have reached the leaf node, plant the * users pointer and return the raw id. */ p->ary[m] = (struct idr_layer *)ptr; set_bit(m, p->bitmap); p->count++; /* * If this layer is full mark the bit in the layer above * to show that this part of the radix tree is full. * This may complete the layer above and require walking * up the radix tree. */ n = id; while (p->bitmap == IDR_FULL) { if (!(p = pa[++l])) break; n = n >> IDR_BITS; set_bit((n & IDR_MASK), p->bitmap); } return(id); } static int idr_get_new_above_int(struct idr_context *idp, void *ptr, int starting_id) { struct idr_layer *p, *new; int layers, v, id; idr_pre_get(idp); id = starting_id; build_up: p = idp->top; layers = idp->layers; if (!p) { if (!(p = alloc_layer(idp))) return -1; layers = 1; } /* * Add a new layer to the top of the tree if the requested * id is larger than the currently allocated space. */ while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) { layers++; if (!p->count) continue; if (!(new = alloc_layer(idp))) { /* * The allocation failed. If we built part of * the structure tear it down. */ for (new = p; p && p != idp->top; new = p) { p = p->ary[0]; new->ary[0] = NULL; new->bitmap = new->count = 0; free_layer(idp, new); } return -1; } new->ary[0] = p; new->count = 1; if (p->bitmap == IDR_FULL) set_bit(0, new->bitmap); p = new; } idp->top = p; idp->layers = layers; v = sub_alloc(idp, ptr, &id); if (v == -2) goto build_up; return(v); } static int sub_remove(struct idr_context *idp, int shift, int id) { struct idr_layer *p = idp->top; struct idr_layer **pa[1+MAX_LEVEL]; struct idr_layer ***paa = &pa[0]; int n; *paa = NULL; *++paa = &idp->top; while ((shift > 0) && p) { n = (id >> shift) & IDR_MASK; clear_bit(n, p->bitmap); *++paa = &p->ary[n]; p = p->ary[n]; shift -= IDR_BITS; } n = id & IDR_MASK; if (p != NULL && test_bit(n, p->bitmap)) { clear_bit(n, p->bitmap); p->ary[n] = NULL; while(*paa && ! --((**paa)->count)){ free_layer(idp, **paa); **paa-- = NULL; } if ( ! *paa ) idp->layers = 0; return 0; } return -1; } static void *_idr_find(struct idr_context *idp, int id) { int n; struct idr_layer *p; n = idp->layers * IDR_BITS; p = idp->top; /* * This tests to see if bits outside the current tree are * present. If so, tain't one of ours! */ if (n + IDR_BITS < 31 && ((id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))) { return NULL; } /* Mask off upper bits we don't use for the search. */ id &= MAX_ID_MASK; while (n >= IDR_BITS && p) { n -= IDR_BITS; p = p->ary[(id >> n) & IDR_MASK]; } return((void *)p); } static int _idr_remove(struct idr_context *idp, int id) { struct idr_layer *p; /* Mask off upper bits we don't use for the search. */ id &= MAX_ID_MASK; if (sub_remove(idp, (idp->layers - 1) * IDR_BITS, id) == -1) { return -1; } if ( idp->top && idp->top->count == 1 && (idp->layers > 1) && idp->top->ary[0]) { /* We can drop a layer */ p = idp->top->ary[0]; idp->top->bitmap = idp->top->count = 0; free_layer(idp, idp->top); idp->top = p; --idp->layers; } while (idp->id_free_cnt >= IDR_FREE_MAX) { p = alloc_layer(idp); talloc_free(p); } return 0; } /************************************************************************ this is the public interface **************************************************************************/ /** initialise a idr tree. The context return value must be passed to all subsequent idr calls. To destroy the idr tree use talloc_free() on this context */ _PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx) { return talloc_zero(mem_ctx, struct idr_context); } /** allocate the next available id, and assign 'ptr' into its slot. you can retrieve later this pointer using idr_find() */ _PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit) { int ret = idr_get_new_above_int(idp, ptr, 0); if (ret > limit) { idr_remove(idp, ret); return -1; } return ret; } /** allocate a new id, giving the first available value greater than or equal to the given starting id */ _PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit) { int ret = idr_get_new_above_int(idp, ptr, starting_id); if (ret > limit) { idr_remove(idp, ret); return -1; } return ret; } /** find a pointer value previously set with idr_get_new given an id */ _PUBLIC_ void *idr_find(struct idr_context *idp, int id) { return _idr_find(idp, id); } /** remove an id from the idr tree */ _PUBLIC_ int idr_remove(struct idr_context *idp, int id) { int ret; ret = _idr_remove((struct idr_context *)idp, id); if (ret != 0) { DEBUG(0,("WARNING: attempt to remove unset id %d in idtree\n", id)); } return ret; } ctdb-2.5.1.dfsg/lib/util/substitute.c0000644000175000017500000000764112245023514017337 0ustar mathieumathieu/* Unix SMB/CIFS implementation. Samba utility functions Copyright (C) Andrew Tridgell 1992-2001 Copyright (C) Simo Sorce 2001-2002 Copyright (C) Martin Pool 2003 Copyright (C) James Peach 2005 This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #include "includes.h" /** * @file * @brief Substitute utilities. **/ /** Substitute a string for a pattern in another string. Make sure there is enough room! This routine looks for pattern in s and replaces it with insert. It may do multiple replacements. Any of " ; ' $ or ` in the insert string are replaced with _ if len==0 then the string cannot be extended. This is different from the old use of len==0 which was for no length checks to be done. **/ _PUBLIC_ void string_sub(char *s, const char *pattern, const char *insert, size_t len) { char *p; ssize_t ls, lp, li, i; if (!insert || !pattern || !*pattern || !s) return; ls = (ssize_t)strlen(s); lp = (ssize_t)strlen(pattern); li = (ssize_t)strlen(insert); if (len == 0) len = ls + 1; /* len is number of *bytes* */ while (lp <= ls && (p = strstr(s, pattern))) { if (ls + (li-lp) >= len) { DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n", (int)(ls + (li-lp) - len), pattern, (int)len)); break; } if (li != lp) { memmove(p+li,p+lp,strlen(p+lp)+1); } for (i=0;i= len) { DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n", (int)(ls + (li-lp) - len), pattern, (int)len)); break; } if (li != lp) { memmove(p+li,p+lp,strlen(p+lp)+1); } memcpy(p, insert, li); s = p + li; ls += (li-lp); } } ctdb-2.5.1.dfsg/lib/util/util_time.c0000644000175000017500000000434512245023514017115 0ustar mathieumathieu/* functions taken from samba4 for quick prototyping of ctdb. These are not intended to remain part of ctdb */ #include "includes.h" #include "system/time.h" #include "system/filesys.h" /** return a zero timeval */ struct timeval timeval_zero(void) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; return tv; } /** return True if a timeval is zero */ bool timeval_is_zero(const struct timeval *tv) { return tv->tv_sec == 0 && tv->tv_usec == 0; } /** return a timeval for the current time */ struct timeval timeval_current(void) { struct timeval tv; gettimeofday(&tv, NULL); return tv; } double timeval_elapsed(struct timeval *tv) { struct timeval tv2 = timeval_current(); return (tv2.tv_sec - tv->tv_sec) + (tv2.tv_usec - tv->tv_usec)*1.0e-6; } double timeval_delta(struct timeval *tv2, struct timeval *tv) { return (tv2->tv_sec - tv->tv_sec) + (tv2->tv_usec - tv->tv_usec)*1.0e-6; } /** return a timeval struct with the given elements */ _PUBLIC_ struct timeval timeval_set(uint32_t secs, uint32_t usecs) { struct timeval tv; tv.tv_sec = secs; tv.tv_usec = usecs; return tv; } _PUBLIC_ int timeval_compare(const struct timeval *tv1, const struct timeval *tv2) { if (tv1->tv_sec > tv2->tv_sec) return 1; if (tv1->tv_sec < tv2->tv_sec) return -1; if (tv1->tv_usec > tv2->tv_usec) return 1; if (tv1->tv_usec < tv2->tv_usec) return -1; return 0; } _PUBLIC_ struct timeval timeval_until(const struct timeval *tv1, const struct timeval *tv2) { struct timeval t; if (timeval_compare(tv1, tv2) >= 0) { return timeval_zero(); } t.tv_sec = tv2->tv_sec - tv1->tv_sec; if (tv1->tv_usec > tv2->tv_usec) { t.tv_sec--; t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec); } else { t.tv_usec = tv2->tv_usec - tv1->tv_usec; } return t; } static struct timeval timeval_add(const struct timeval *tv, uint32_t secs, uint32_t usecs) { struct timeval tv2 = *tv; const unsigned int million = 1000000; tv2.tv_sec += secs; tv2.tv_usec += usecs; tv2.tv_sec += tv2.tv_usec / million; tv2.tv_usec = tv2.tv_usec % million; return tv2; } _PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs) { struct timeval tv = timeval_current(); return timeval_add(&tv, secs, usecs); } ctdb-2.5.1.dfsg/config.sub0000644000175000017500000010554612245023514015220 0ustar mathieumathieu#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013 Free Software Foundation, Inc. timestamp='2013-01-11' # This file 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 3 of the License, or # (at your option) any later version. # # This program 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 this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ctdb-2.5.1.dfsg/utils/0000755000175000017500000000000012245023514014365 5ustar mathieumathieuctdb-2.5.1.dfsg/utils/smnotify/0000755000175000017500000000000012245023514016235 5ustar mathieumathieuctdb-2.5.1.dfsg/utils/smnotify/smnotify.c0000644000175000017500000000741612245023514020261 0ustar mathieumathieu/* simple smnotify tool Copyright (C) Ronnie Sahlberg 2007 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #include #include #include #include #include #include #include #include "smnotify.h" #include "popt.h" static char *client = NULL; static const char *ip = NULL; static char *server = NULL; static int stateval = 0; static int clientport = 0; static int sendport = 0; static void useage(void) { exit(0); } static int create_socket(const char *addr, int port) { int s; struct sockaddr_in sock_in; s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) { printf("Failed to open local socket\n"); exit(10); } bzero(&sock_in, sizeof(sock_in)); sock_in.sin_family = PF_INET; sock_in.sin_port = htons(port); inet_aton(addr, &sock_in.sin_addr); if (bind(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) == -1) { printf("Failed to bind to local socket\n"); exit(10); } return s; } int main(int argc, const char *argv[]) { struct poptOption popt_options[] = { POPT_AUTOHELP { "client", 'c', POPT_ARG_STRING, &client, 0, "remote client to send the notify to", "hostname/ip" }, { "clientport", 0, POPT_ARG_INT, &clientport, 0, "clientport", "integer" }, { "ip", 'i', POPT_ARG_STRING, &ip, 0, "local ip address to send the notification from", "ip" }, { "sendport", 0, POPT_ARG_INT, &sendport, 0, "port to send the notify from", "integer" }, { "server", 's', POPT_ARG_STRING, &server, 0, "servername to use in the notification", "hostname/ip" }, { "stateval", 0, POPT_ARG_INT, &stateval, 0, "stateval", "integer" }, POPT_TABLEEND }; int opt; poptContext pc; CLIENT *clnt; int s; struct sockaddr_in sock_cl; struct timeval w; struct status st; pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { default: fprintf(stderr, "Invalid option %s: %s\n", poptBadOption(pc, 0), poptStrerror(opt)); exit(1); } } if (client == NULL) { printf("ERROR: client not specified\n"); useage(); } if (ip == NULL) { printf("ERROR: ip not specified\n"); useage(); } if (server == NULL) { printf("ERROR: server not specified\n"); useage(); } if (stateval == 0) { printf("ERROR: stateval not specified\n"); useage(); } /* Since we want to control from which address these packets are sent we must create the socket ourself and use low-level rpc calls. */ s = create_socket(ip, sendport); /* only wait for at most 3 seconds before giving up */ alarm(3); /* Setup a sockaddr_in for the client we want to notify */ bzero(&sock_cl, sizeof(sock_cl)); sock_cl.sin_family = PF_INET; sock_cl.sin_port = htons(clientport); inet_aton(client, &sock_cl.sin_addr); w.tv_sec = 1; w.tv_usec= 0; clnt = clntudp_create(&sock_cl, 100024, 1, w, &s); if (clnt == NULL) { printf("ERROR: failed to connect to client\n"); exit(10); } /* we dont want to wait for any reply */ w.tv_sec = 0; w.tv_usec = 0; clnt_control(clnt, CLSET_TIMEOUT, (char *)&w); st.mon_name=server; st.state=stateval; sm_notify_1(&st, clnt); return 0; } ctdb-2.5.1.dfsg/utils/smnotify/smnotify.x0000644000175000017500000000043412245023514020277 0ustar mathieumathieu#ifdef RPC_HDR %#ifdef _AIX %#include %#endif /* _AIX */ #endif /* RPC_HDR */ const SM_MAXSTRLEN = 1024; struct status { string mon_name; int state; }; program SMNOTIFY { version SMVERSION { void SM_NOTIFY(struct status) = 6; } = 1; } = 100024; ctdb-2.5.1.dfsg/utils/ping_pong/0000755000175000017500000000000012245023514016345 5ustar mathieumathieuctdb-2.5.1.dfsg/utils/ping_pong/ping_pong.c0000644000175000017500000001236012245023514020473 0ustar mathieumathieu/* A ping-pong fcntl byte range lock test Copyright (C) Andrew Tridgell 2002 Copyright (C) Michael Adam 2012 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ /* This measures the ping-pong byte range lock latency. It is especially useful on a cluster of nodes sharing a common lock manager as it will give some indication of the lock managers performance under stress. tridge@samba.org, February 2002 */ #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include static struct timeval tp1,tp2; static int do_reads, do_writes, use_mmap, do_check; static void start_timer(void) { gettimeofday(&tp1,NULL); } static double end_timer(void) { gettimeofday(&tp2,NULL); return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - (tp1.tv_sec + (tp1.tv_usec*1.0e-6)); } /* lock a byte range in a open file */ static int lock_range(int fd, int offset, int len) { struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = offset; lock.l_len = len; lock.l_pid = 0; return fcntl(fd,F_SETLKW,&lock); } /* check whether we could place a lock */ int check_lock(int fd, int offset, int len) { struct flock lock; int ret; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = offset; lock.l_len = len; lock.l_pid = 0; ret = fcntl(fd, F_GETLK, &lock); if (ret != 0) { printf("error calling fcntl F_GETLCK: %s\n", strerror(errno)); return -1; } if (lock.l_type == F_UNLCK) { /* we would be able to place the lock */ return 0; } /* we would not be able to place lock */ printf("check_lock failed: lock held: " "pid='%d', type='%d', start='%d', len='%d'\n", (int)lock.l_pid, (int)lock.l_type, (int)lock.l_start, (int)lock.l_len); return 1; } /* unlock a byte range in a open file */ static int unlock_range(int fd, int offset, int len) { struct flock lock; lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = offset; lock.l_len = len; lock.l_pid = 0; return fcntl(fd,F_SETLKW,&lock); } /* run the ping pong test on fd */ static void ping_pong(int fd, int num_locks) { unsigned count = 0; int i=0, loops=0; unsigned char *val; unsigned char incr=0, last_incr=0; unsigned char *p = NULL; int ret; ret = ftruncate(fd, num_locks+1); if (ret == -1) { printf("ftruncate failed: %s\n", strerror(errno)); return; } if (use_mmap) { p = mmap(NULL, num_locks+1, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { printf("mmap failed: %s\n", strerror(errno)); return; } } val = (unsigned char *)calloc(num_locks+1, sizeof(unsigned char)); if (val == NULL) { printf("calloc failed\n"); return; } start_timer(); lock_range(fd, 0, 1); i = 0; while (1) { if (lock_range(fd, (i+1) % num_locks, 1) != 0) { printf("lock at %d failed! - %s\n", (i+1) % num_locks, strerror(errno)); } if (do_check) { ret = check_lock(fd, i, 1); } if (do_reads) { unsigned char c; if (use_mmap) { c = p[i]; } else if (pread(fd, &c, 1, i) != 1) { printf("read failed at %d\n", i); } incr = c - val[i]; val[i] = c; } if (do_writes) { char c = val[i] + 1; if (use_mmap) { p[i] = c; } else if (pwrite(fd, &c, 1, i) != 1) { printf("write failed at %d\n", i); } } if (unlock_range(fd, i, 1) != 0) { printf("unlock at %d failed! - %s\n", i, strerror(errno)); } i = (i+1) % num_locks; count++; if (loops > num_locks && incr != last_incr) { last_incr = incr; printf("data increment = %u\n", incr); fflush(stdout); } if (end_timer() > 1.0) { printf("%8u locks/sec\r", (unsigned)(2*count/end_timer())); fflush(stdout); start_timer(); count=0; } loops++; } } int main(int argc, char *argv[]) { char *fname; int fd, num_locks; int c; while ((c = getopt(argc, argv, "rwmc")) != -1) { switch (c){ case 'w': do_writes = 1; break; case 'r': do_reads = 1; break; case 'm': use_mmap = 1; break; case 'c': do_check = 1; break; default: fprintf(stderr, "Unknown option '%c'\n", c); exit(1); } } argv += optind; argc -= optind; if (argc < 2) { printf("ping_pong [options] \n"); printf(" -r do reads\n"); printf(" -w do writes\n"); printf(" -m use mmap\n"); printf(" -c check locks\n"); exit(1); } fname = argv[0]; num_locks = atoi(argv[1]); if (num_locks <= 0) { printf("num_locks should be > 0\n"); exit(1); } fd = open(fname, O_CREAT|O_RDWR, 0600); if (fd == -1) exit(1); ping_pong(fd, num_locks); return 0; } ctdb-2.5.1.dfsg/utils/scsi_io/0000755000175000017500000000000012245023514016015 5ustar mathieumathieuctdb-2.5.1.dfsg/utils/scsi_io/scsi_io.c0000644000175000017500000006344412245023514017624 0ustar mathieumathieu/* a tool to open a scsi device and issue some useful commands such as INQUIRY and helpers to call various PERSISTENT RESERVATION functions Copyright ronnie sahlberg 2007 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ /* very incomplete and needs to be enhanced with noice command line options to drive it. we need access to an array that supports the PERSISTENT RESERVATION cdb's before we can proceed */ /* scsi bugs: INQUIRY takes a 2 byte allocation_length parameter but it appears that it only looks at the low byte. If you specify 0x00ff all is well but if you specify 0x0100 it gets confused and returnes garbage data for (e.g) SupportedVPDPages. Same goes for UnitSerialNumber and probably all other inq pages as well. */ #include #include #include #include #include #include #include #include "popt.h" #define SCSI_TIMEOUT 5000 /* ms */ static char *command = NULL; static char *device = NULL; static char *key = NULL; static char *rmkey = NULL; static int scope = -1; static int type = -1; const char *sensetable[16]={ "no sense", "recovered error", "not ready", "medium error", "hardware error", "illegal request", "unit attention", "data protect", "blank check", "vendor specific", "copy aborted", "aboreted command", "unknown", "unknown", "unknown", "unknown" }; int scsi_io(int fd, unsigned char *cdb, unsigned char cdb_size, int xfer_dir, unsigned char *data, unsigned int *data_size, unsigned char *sense, unsigned int *sense_len) { sg_io_hdr_t io_hdr; memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; /* CDB */ io_hdr.cmdp = cdb; io_hdr.cmd_len = cdb_size; /* Where to store the sense_data, if there was an error */ io_hdr.sbp = sense; io_hdr.mx_sb_len = *sense_len; *sense_len=0; /* Transfer direction, either in or out. Linux does not yet support bidirectional SCSI transfers ? */ io_hdr.dxfer_direction = xfer_dir; /* Where to store the DATA IN/OUT from the device and how big the buffer is */ io_hdr.dxferp = data; io_hdr.dxfer_len = *data_size; /* SCSI timeout in ms */ io_hdr.timeout = SCSI_TIMEOUT; if(ioctl(fd, SG_IO, &io_hdr) < 0){ perror("SG_IO ioctl failed"); return -1; } /* now for the error processing */ if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK){ if(io_hdr.sb_len_wr > 0){ *sense_len=io_hdr.sb_len_wr; return 0; } } if(io_hdr.masked_status){ printf("status=0x%x\n", io_hdr.status); printf("masked_status=0x%x\n", io_hdr.masked_status); return -2; } if(io_hdr.host_status){ printf("host_status=0x%x\n", io_hdr.host_status); return -3; } if(io_hdr.driver_status){ printf("driver_status=0x%x\n", io_hdr.driver_status); return -4; } #if 0 {int i; printf("CDB:\n"); for(i=0;istring){ if(vs->value==v){ return vs->string; } vs++; } return ""; } void print_sense_data(unsigned char *sense, int sense_len) { int i; unsigned char asc, ascq; printf("Device returned sense information\n"); if(sense[0]==0x70){ printf("filemark:%d eom:%d ili:%d sense-key:0x%02x (%s)\n", !!(sense[2]&0x80), !!(sense[2]&0x40), !!(sense[2]&0x20), sense[2]&0x0f, sensetable[sense[2]&0x0f]); printf("command specific info: 0x%02x 0x%02x 0x%02x 0x%02x\n", sense[8],sense[9],sense[10],sense[11]); asc=sense[12]; printf("additional sense code:0x%02x\n", asc); ascq=sense[13]; printf("additional sense code qualifier:0x%02x\n", ascq); printf("field replacable unit code:0x%02x\n", sense[14]); if((asc==0x20)&&(ascq==0x00)) printf("INVALID COMMAND OPERATION CODE\n"); } printf("Sense data:\n"); for(i=0;i>8)&0xff; cdb[4]=data_size&0xff; printf("Standard INQUIRY Data:\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } /* Peripheral Qualifier */ printf("Peripheral Qualifier:%c%c%cb\n", '0'+!!(data[0]&0x80), '0'+!!(data[0]&0x40), '0'+!!(data[0]&0x20)); /* Peripheral Device Type */ printf("Peripheral Device Type: 0x%02x (%s)\n", data[0]&0x1f, val_to_str(peripheral_device_types, data[0]&0x1f)); /* RMB */ printf("RMB: %s device\n", data[1]&0x80?"REMOVABLE":"NON-REMOVABLE"); /* SCSI Version */ printf("SCSI Version: 0x%02x (%s)\n", data[2], val_to_str(scsi_versions, data[2])); /* NormACA, HiSUP, Response Data Format */ printf("NormACA:%d HiSup:%d ResponseDataFormat:%d\n", !!(data[3]&0x20), !!(data[3]&0x10), data[3]&0x0f); switch(data[3]&0x0f){ /*SPC-2/SPC-3/SPC-4*/ case 2: /*SPC (not strictly correct but we print it like 2 anyway)*/ case 1: /* SCCS ... */ printf("SCCS:%d ACC:%d TPGS:%c%cb 3PC:%d PROTECT:%d\n", !!(data[5]&0x80), !!(data[5]&0x40), '0'+!!(data[5]&0x20), '0'+!!(data[5]&0x10), !!(data[5]&0x08), !!(data[5]&0x01)); /* Encserv ... */ printf("Encserv:%d VS:%d MultiP:%d ADDR16:%d\n", !!(data[6]&0x40), !!(data[6]&0x20), !!(data[6]&0x10), !!(data[6]&0x01)); /* WBUS16 ... */ printf("WBUS16:%d SYNC:%d CmdQue:%d VS:%d\n", !!(data[7]&0x20), !!(data[7]&0x10), !!(data[7]&0x02), !!(data[7]&0x01)); /* T10 vendor Identification */ printf("Vendor:"); for(i=0;i<8;i++)printf("%c",data[8+i]);printf("\n"); /* Product Identification */ printf("Product:"); for(i=0;i<16;i++)printf("%c",data[16+i]);printf("\n"); /* Product Revision Level */ printf("Product Revision:"); for(i=0;i<4;i++)printf("%c",data[32+i]);printf("\n"); break; } return 0; } int scsi_inquiry_supported_vpd_pages(int fd) { unsigned char cdb[]={0x12,0x01,0,0,0,0}; unsigned int data_size=0xff; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; int res, pl, i; cdb[3]=(data_size>>8)&0xff; cdb[4]=data_size&0xff; printf("INQUIRY Supported VPD Pages:\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } /* Page Length */ pl=data[3]; /* Pages */ for(i=4;i<(pl+4);i++){ printf("Page:%02xh (%s)\n", data[i], val_to_str(vpd_pages, data[i])); } return 0; } int scsi_inquiry_unit_serial_number(int fd) { unsigned char cdb[]={0x12,0x01,0x80,0,0,0}; unsigned int data_size=0x00ff; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; int res, pl, i; cdb[3]=(data_size>>8)&0xff; cdb[4]=data_size&0xff; printf("INQUIRY Unit Serial Number:\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } /* Page Length */ pl=data[3]; /* Unit Serial Number */ printf("Unit Serial Number:"); for(i=4;i<(pl+4);i++)printf("%c",data[i]&0xff);printf("\n"); return 0; } int scsi_persistent_reserve_in_read_keys(int fd) { unsigned char cdb[]={0x5e,0,0,0,0,0,0,0,0,0}; unsigned int data_size=0x00ff; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; unsigned char service_action=0; int res, i; unsigned long prgeneration, additional_length; cdb[1]=service_action; cdb[7]=(data_size>>8)&0xff; cdb[8]=data_size&0xff; printf("PRESISTENT RESERVE IN: READ KEYS\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } /* PRGeneration */ prgeneration=data[0]; prgeneration<<=8;prgeneration|=data[1]; prgeneration<<=8;prgeneration|=data[2]; prgeneration<<=8;prgeneration|=data[3]; printf("PRGeneration:%lu\n", prgeneration); /* Additional Length */ additional_length=data[4]; additional_length<<=8;additional_length|=data[5]; additional_length<<=8;additional_length|=data[6]; additional_length<<=8;additional_length|=data[7]; printf("Additional Length:%lu\n", additional_length); /* print the registered keys */ for(i=0;i>8)&0xff; cdb[8]=data_size&0xff; printf("PRESISTENT RESERVE IN: READ RESERVATION\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } /* PRGeneration */ prgeneration=data[0]; prgeneration<<=8;prgeneration|=data[1]; prgeneration<<=8;prgeneration|=data[2]; prgeneration<<=8;prgeneration|=data[3]; printf("PRGeneration:%lu\n", prgeneration); /* Additional Length */ additional_length=data[4]; additional_length<<=8;additional_length|=data[5]; additional_length<<=8;additional_length|=data[6]; additional_length<<=8;additional_length|=data[7]; printf("Additional Length:%lu\n", additional_length); if(additional_length==16){ printf("Key:%02x%02x%02x%02x%02x%02x%02x%02x\n", data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]); printf("Scope:%xh Type:%xh\n",data[21]>>4,data[21]&0x0f); } return 0; } int scsi_persistent_reserve_in_report_capabilities(int fd) { unsigned char cdb[]={0x5e,0,0,0,0,0,0,0,0,0}; unsigned int data_size=0x00ff; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; unsigned char service_action=2; int res; unsigned short length, type_mask; cdb[1]=service_action; cdb[7]=(data_size>>8)&0xff; cdb[8]=data_size&0xff; printf("PRESISTENT RESERVE IN: REPORT CAPABILITIES\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } /* Length */ length=data[0]; length<<=8;length|=data[1]; printf("Length:%d\n", length); /* CRH ... */ printf("CRH:%d SIP_C:%d ATP_C:%d PTPL_C:%d\n", !!(data[2]&0x10), !!(data[2]&0x08), !!(data[2]&0x04), !!(data[2]&0x01)); /* TMV ... */ printf("TMV:%d ALLOW_COMMANDS:%c%c%cb PTPL_A:%d\n", !!(data[3]&0x80), '0'+(!!(data[3]&0x40)), '0'+(!!(data[3]&0x20)), '0'+(!!(data[3]&0x10)), !!(data[3]&0x01)); /* Persistent Reservation Type Mask */ type_mask=data[4]; type_mask<<=8;type_mask|=data[5]; printf("Presistent Reservation Type Mask:0x%04x\n", type_mask); printf("WR_EX_AR:%d EX_AC_RO:%d WR_EX_RO:%d EX_AC:%d WR_EX:%d EX_AC_AR:%d\n", !!(data[4]&0x80), !!(data[4]&0x40), !!(data[4]&0x20), !!(data[4]&0x08), !!(data[4]&0x02), !!(data[4]&0x01)); return 0; } int scsi_persistent_reserve_in_read_full_status(int fd) { unsigned char cdb[]={0x5e,0,0,0,0,0,0,0,0,0}; unsigned int data_size=0x00ff; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; unsigned char service_action=3; int res; unsigned long prgeneration, additional_length; cdb[1]=service_action; cdb[7]=(data_size>>8)&0xff; cdb[8]=data_size&0xff; printf("PRESISTENT RESERVE IN: READ FULL STATUS\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } /* PRGeneration */ prgeneration=data[0]; prgeneration<<=8;prgeneration|=data[1]; prgeneration<<=8;prgeneration|=data[2]; prgeneration<<=8;prgeneration|=data[3]; printf("PRGeneration:%lu\n", prgeneration); /* Additional Length */ additional_length=data[4]; additional_length<<=8;additional_length|=data[5]; additional_length<<=8;additional_length|=data[6]; additional_length<<=8;additional_length|=data[7]; printf("Additional Length:%lu\n", additional_length); /*XXX*/ return 0; } int scsi_persistent_reserve_out_clear(int fd) { unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0}; unsigned int data_size=24; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; unsigned char service_action=3; int res; long long k; if (scope==-1) { printf("Must specify scope\n"); printf("scsi_io --device= --command=clear --scope= --type= --key=\n"); _exit(10); } if (type==-1) { printf("Must specify type\n"); printf("scsi_io --device= --command=clear --scope= --type= --key=\n"); _exit(10); } if (!key) { printf("Must specify key\n"); printf("scsi_io --device= --command=clear --scope= --type= --key=\n"); _exit(10); } sscanf(key, "%llx", &k); cdb[1]=service_action; cdb[2]=(scope<<4)|type; cdb[7]=(data_size>>8)&0xff; cdb[8]=data_size&0xff; memset(data, 0, data_size); /* Reservation Key */ data[0]=(k>>56)&0xff; data[1]=(k>>48)&0xff; data[2]=(k>>40)&0xff; data[3]=(k>>32)&0xff; data[4]=(k>>24)&0xff; data[5]=(k>>16)&0xff; data[6]=(k>> 8)&0xff; data[7]=(k )&0xff; /* Service Action Key */ data[8]=0; data[9]=0; data[10]=0; data[11]=0; data[12]=0; data[13]=0; data[14]=0; data[15]=0; /* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */ data[20]=0x04; printf("PRESISTENT RESERVE IN: CLEAR\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } return 0; } int scsi_persistent_reserve_out_reserve(int fd) { unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0}; unsigned int data_size=24; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; unsigned char service_action=1; int res; long long k; if (scope==-1) { printf("Must specify scope\n"); printf("scsi_io --device= --command=reserve --scope= --type= --key=\n"); _exit(10); } if (type==-1) { printf("Must specify type\n"); printf("scsi_io --device= --command=reserve --scope= --type= --key=\n"); _exit(10); } if (!key) { printf("Must specify key\n"); printf("scsi_io --device= --command=reserve --scope= --type= --key=\n"); _exit(10); } sscanf(key, "%llx", &k); cdb[1]=service_action; cdb[2]=(scope<<4)|type; cdb[7]=(data_size>>8)&0xff; cdb[8]=data_size&0xff; memset(data, 0, data_size); /* Reservation Key */ data[0]=(k>>56)&0xff; data[1]=(k>>48)&0xff; data[2]=(k>>40)&0xff; data[3]=(k>>32)&0xff; data[4]=(k>>24)&0xff; data[5]=(k>>16)&0xff; data[6]=(k>> 8)&0xff; data[7]=(k )&0xff; /* Service Action Key */ data[8]=0; data[9]=0; data[10]=0; data[11]=0; data[12]=0; data[13]=0; data[14]=0; data[15]=0; /* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */ data[20]=0x04; printf("PRESISTENT RESERVE IN: RESERVE\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } return 0; } int scsi_persistent_reserve_out_preempt(int fd) { unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0}; unsigned int data_size=24; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; unsigned char service_action=4; int res; long long k; if (scope==-1) { printf("Must specify scope\n"); printf("scsi_io --device= --command=preempt --scope= --type= --key= --rmkey=\n"); _exit(10); } if (type==-1) { printf("Must specify type\n"); printf("scsi_io --device= --command=preempt --scope= --type= --key= --rmkey=\n"); _exit(10); } if (!key) { printf("Must specify key\n"); printf("scsi_io --device= --command=preempt --scope= --type= --key= --rmkey=\n"); _exit(10); } if (!rmkey) { printf("Must specify rmkey\n"); printf("scsi_io --device= --command=preempt --scope= --type= --key= --rmkey=\n"); _exit(10); } cdb[1]=service_action; cdb[2]=(scope<<4)|type; cdb[7]=(data_size>>8)&0xff; cdb[8]=data_size&0xff; memset(data, 0, data_size); /* Reservation Key */ sscanf(key, "%llx", &k); data[0]=(k>>56)&0xff; data[1]=(k>>48)&0xff; data[2]=(k>>40)&0xff; data[3]=(k>>32)&0xff; data[4]=(k>>24)&0xff; data[5]=(k>>16)&0xff; data[6]=(k>> 8)&0xff; data[7]=(k )&0xff; /* Service Action Key */ sscanf(rmkey, "%llx", &k); data[8] =(k>>56)&0xff; data[9] =(k>>48)&0xff; data[10]=(k>>40)&0xff; data[11]=(k>>32)&0xff; data[12]=(k>>24)&0xff; data[13]=(k>>16)&0xff; data[14]=(k>> 8)&0xff; data[15]=(k )&0xff; /* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */ data[20]=0x04; printf("PRESISTENT RESERVE IN: RESERVE\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } return 0; } int scsi_persistent_reserve_out_register_and_ignore_existing_key(int fd) { unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0}; unsigned int data_size=24; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; unsigned char service_action=6; int res; long long k; if (scope==-1) { printf("Must specify scope\n"); printf("scsi_io --device= --command=registerkey --scope= --type= --key=\n"); _exit(10); } if (type==-1) { printf("Must specify type\n"); printf("scsi_io --device= --command=registerkey --scope= --type= --key=\n"); _exit(10); } if (!key) { printf("Must specify key\n"); printf("scsi_io --device= --command=registerkey --scope= --type= --key=\n"); _exit(10); } sscanf(key, "%llx", &k); cdb[1]=service_action; cdb[2]=(scope<<4)|type; cdb[7]=(data_size>>8)&0xff; cdb[8]=data_size&0xff; memset(data, 0, data_size); /* Reservation Key */ data[0]=0; data[1]=0; data[2]=0; data[3]=0; data[4]=0; data[5]=0; data[6]=0; data[7]=0; /* Service Action Key */ data[8] =(k>>56)&0xff; data[9] =(k>>48)&0xff; data[10]=(k>>40)&0xff; data[11]=(k>>32)&0xff; data[12]=(k>>24)&0xff; data[13]=(k>>16)&0xff; data[14]=(k>> 8)&0xff; data[15]=(k )&0xff; /* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */ data[20]=0x04; printf("PRESISTENT RESERVE IN: REGISTER AND IGNORE EXISTING KEY\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } return 0; } int scsi_persistent_reserve_out_unregister_key(int fd) { unsigned char cdb[]={0x5f,0,0,0,0,0,0,0,0,0}; unsigned int data_size=24; unsigned char data[data_size]; unsigned int sense_len=32; unsigned char sense[sense_len]; unsigned char service_action=6; int res; long long k; if (scope==-1) { printf("Must specify scope\n"); printf("scsi_io --device= --command=unregisterkey --scope= --type= --key=\n"); _exit(10); } if (type==-1) { printf("Must specify type\n"); printf("scsi_io --device= --command=unregisterkey --scope= --type= --key=\n"); _exit(10); } if (!key) { printf("Must specify key\n"); printf("scsi_io --device= --command=unregisterkey --scope= --type= --key=\n"); _exit(10); } sscanf(key, "%llx", &k); cdb[1]=service_action; cdb[2]=(scope<<4)|type; cdb[7]=(data_size>>8)&0xff; cdb[8]=data_size&0xff; memset(data, 0, data_size); /* Reservation Key */ data[0]=(k>>56)&0xff; data[1]=(k>>48)&0xff; data[2]=(k>>40)&0xff; data[3]=(k>>32)&0xff; data[4]=(k>>24)&0xff; data[5]=(k>>16)&0xff; data[6]=(k>> 8)&0xff; data[7]=(k )&0xff; /* Service Action Key */ data[8]=0; data[9]=0; data[10]=0; data[11]=0; data[12]=0; data[13]=0; data[14]=0; data[15]=0; /* Spec_ip_ti=0 all_tg_pt=1 aptpl=0 */ data[20]=0x04; printf("PRESISTENT RESERVE IN: UNREGISTER KEY\n"); res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, data, &data_size, sense, &sense_len); if(res){ printf("SCSI_IO failed\n"); return -1; } if(sense_len){ print_sense_data(sense, sense_len); return -1; } return 0; } int open_scsi_device(const char *dev) { int fd, vers; if((fd=open(dev, O_RDWR))<0){ printf("ERROR could not open device %s\n", dev); return -1; } if ((ioctl(fd, SG_GET_VERSION_NUM, &vers) < 0) || (vers < 30000)) { printf("/dev is not an sg device, or old sg driver\n"); close(fd); return -1; } return fd; } typedef int (*scsi_func_t)(int fd); typedef struct _cmds_t { const char *cmd; scsi_func_t func; const char *comment; } cmds_t; cmds_t cmds[] = { {"inq", scsi_inquiry, "Standard INQUIRY output"}, {"vpd", scsi_inquiry_supported_vpd_pages, "Supported VPD Pages"}, {"usn", scsi_inquiry_unit_serial_number, "Unit serial number"}, {"readkeys", scsi_persistent_reserve_in_read_keys, "Read SCSI Reservation Keys"}, {"readrsvr", scsi_persistent_reserve_in_read_reservation, "Read SCSI Reservation Data"}, {"reportcap", scsi_persistent_reserve_in_report_capabilities, "Report reservation Capabilities"}, {"registerkey", scsi_persistent_reserve_out_register_and_ignore_existing_key, "Register and ignore existing key"}, {"unregisterkey", scsi_persistent_reserve_out_unregister_key, "Unregister a key"}, {"clear", scsi_persistent_reserve_out_clear, "Clear all reservations and registrations"}, {"reserve", scsi_persistent_reserve_out_reserve, "Reserve"}, {"preempt", scsi_persistent_reserve_out_preempt, "Preempt (remove someone elses registration)"}, }; void usage(void) { int i; printf("Usage: scsi_io --command --device \n"); printf("Commands:\n"); for (i=0;i root { ctdb } #include "pmns" ctdb-2.5.1.dfsg/utils/pmda/config.m40000644000175000017500000000120512245023514017013 0ustar mathieumathieuAC_ARG_ENABLE(pmda, AS_HELP_STRING([--enable-pmda], [Turn on PCP pmda support (default=no)])) HAVE_PMDA=no if eval "test x$enable_pmda = xyes"; then HAVE_PMDA=yes AC_CHECK_HEADERS(pcp/pmapi.h pcp/impl.h pcp/pmda.h, [], [AC_MSG_ERROR([Missing PCP pmda headers])], [[#ifdef HAVE_PCP_PMAPI_H # include #endif #ifdef HAVE_PCP_IMPL_H # include #endif #ifdef HAVE_PCP_PMDA_H # include #endif ]]) fi if test x"$HAVE_PMDA" = x"yes"; then CTDB_PMDA=bin/pmdactdb CTDB_PMDA_INSTALL=install_pmda else CTDB_PMDA= CTDB_PMDA_INSTALL= fi AC_SUBST(CTDB_PMDA) AC_SUBST(CTDB_PMDA_INSTALL) ctdb-2.5.1.dfsg/utils/pmda/pmda_ctdb.c0000644000175000017500000003570712245023514017403 0ustar mathieumathieu/* * CTDB Performance Metrics Domain Agent (PMDA) for Performance Co-Pilot (PCP) * * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2011 David Disseldorp * * This program 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 of the License, or (at your * option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "../../include/includes.h" #include "../../include/ctdb.h" #include "../../include/ctdb_private.h" #include "../../include/ctdb_protocol.h" #include "domain.h" /* * CTDB PMDA * * This PMDA connects to the locally running ctdbd daemon and pulls * statistics for export via PCP. The ctdbd Unix domain socket path can be * specified with the CTDB_SOCKET environment variable, otherwise the default * path is used. */ /* * All metrics supported in this PMDA - one table entry for each. * The 4th field specifies the serial number of the instance domain * for the metric, and must be either PM_INDOM_NULL (denoting a * metric that only ever has a single value), or the serial number * of one of the instance domains declared in the instance domain table * (i.e. in indomtab, above). */ static pmdaMetric metrictab[] = { /* num_clients */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* frozen */ { NULL, { PMDA_PMID(1,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* recovering */ { NULL, { PMDA_PMID(3,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* client_packets_sent */ { NULL, { PMDA_PMID(4,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* client_packets_recv */ { NULL, { PMDA_PMID(5,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* node_packets_sent */ { NULL, { PMDA_PMID(6,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* node_packets_recv */ { NULL, { PMDA_PMID(7,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* keepalive_packets_sent */ { NULL, { PMDA_PMID(8,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* keepalive_packets_recv */ { NULL, { PMDA_PMID(9,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* req_call */ { NULL, { PMDA_PMID(10,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* reply_call */ { NULL, { PMDA_PMID(10,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* req_dmaster */ { NULL, { PMDA_PMID(10,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* reply_dmaster */ { NULL, { PMDA_PMID(10,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* reply_error */ { NULL, { PMDA_PMID(10,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* req_message */ { NULL, { PMDA_PMID(10,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* req_control */ { NULL, { PMDA_PMID(10,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* reply_control */ { NULL, { PMDA_PMID(10,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* req_call */ { NULL, { PMDA_PMID(11,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* req_message */ { NULL, { PMDA_PMID(11,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* req_control */ { NULL, { PMDA_PMID(11,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* call */ { NULL, { PMDA_PMID(12,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) }, }, /* control */ { NULL, { PMDA_PMID(12,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) }, }, /* traverse */ { NULL, { PMDA_PMID(12,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) }, }, /* total_calls */ { NULL, { PMDA_PMID(13,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* pending_calls */ { NULL, { PMDA_PMID(14,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* locks.num_calls */ { NULL, { PMDA_PMID(15,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* locks.pending_calls */ { NULL, { PMDA_PMID(16,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* childwrite_calls */ { NULL, { PMDA_PMID(17,28), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* pending_childwrite_calls */ { NULL, { PMDA_PMID(18,29), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* memory_used */ { NULL, { PMDA_PMID(19,30), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* max_hop_count */ { NULL, { PMDA_PMID(20,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* max_reclock_ctdbd */ { NULL, { PMDA_PMID(21,32), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, /* max_reclock_recd */ { NULL, { PMDA_PMID(22,33), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, /* max_call_latency */ { NULL, { PMDA_PMID(23,34), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, /* locks.latency.max */ { NULL, { PMDA_PMID(24,35), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, /* childwrite_latency.max */ { NULL, { PMDA_PMID(25,36), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, /* num_recoveries */ { NULL, { PMDA_PMID(26,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; static struct event_context *ev; static struct ctdb_context *ctdb; static struct ctdb_statistics *stats; static void pmda_ctdb_q_read_cb(uint8_t *data, size_t cnt, void *args) { if (cnt == 0) { fprintf(stderr, "ctdbd unreachable\n"); /* cleanup on request timeout */ return; } ctdb_client_read_cb(data, cnt, args); } static int pmda_ctdb_daemon_connect(void) { const char *socket_name; int ret; struct sockaddr_un addr; ev = event_context_init(NULL); if (ev == NULL) { fprintf(stderr, "Failed to init event ctx\n"); return -1; } ctdb = ctdb_init(ev); if (ctdb == NULL) { fprintf(stderr, "Failed to init ctdb\n"); goto err_ev; } socket_name = getenv("CTDB_SOCKET"); if (socket_name == NULL) { socket_name = CTDB_PATH; } ret = ctdb_set_socketname(ctdb, socket_name); if (ret == -1) { fprintf(stderr, "ctdb_set_socketname failed - %s\n", ctdb_errstr(ctdb)); goto err_ctdb; } /* * ctdb_socket_connect() sets a default queue callback handler that * calls exit() if ctdbd is unavailable on recv, use our own wrapper to * work around this */ memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path)); ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0); if (ctdb->daemon.sd == -1) { fprintf(stderr, "Failed to open client socket\n"); goto err_ctdb; } set_nonblocking(ctdb->daemon.sd); set_close_on_exec(ctdb->daemon.sd); if (connect(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { fprintf(stderr, "Failed to connect to ctdb daemon via %s\n", ctdb->daemon.name); goto err_sd; } ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd, CTDB_DS_ALIGNMENT, pmda_ctdb_q_read_cb, ctdb, "to-ctdbd"); if (ctdb->daemon.queue == NULL) { fprintf(stderr, "Failed to setup queue\n"); goto err_sd; } ctdb->pnn = ctdb_ctrl_getpnn(ctdb, timeval_current_ofs(3, 0), CTDB_CURRENT_NODE); if (ctdb->pnn == (uint32_t)-1) { fprintf(stderr, "Failed to get ctdb pnn\n"); goto err_sd; } return 0; err_sd: close(ctdb->daemon.sd); err_ctdb: talloc_free(ctdb); err_ev: talloc_free(ev); ctdb = NULL; return -1; } static void pmda_ctdb_daemon_disconnect(void) { if (ctdb->methods) { ctdb->methods->shutdown(ctdb); } if (ctdb->daemon.sd != -1) { close(ctdb->daemon.sd); } talloc_free(ctdb); talloc_free(ev); ctdb = NULL; } static int fill_node(unsigned int item, pmAtomValue *atom) { switch (item) { case 10: atom->ul = stats->node.req_call; break; case 11: atom->ul = stats->node.reply_call; break; case 12: atom->ul = stats->node.req_dmaster; break; case 13: atom->ul = stats->node.reply_dmaster; break; case 14: atom->ul = stats->node.reply_error; break; case 15: atom->ul = stats->node.req_message; break; case 16: atom->ul = stats->node.req_control; break; case 17: atom->ul = stats->node.reply_control; break; default: return PM_ERR_PMID; } return 0; } static int fill_client(unsigned int item, pmAtomValue *atom) { switch (item) { case 18: atom->ul = stats->client.req_call; break; case 19: atom->ul = stats->client.req_message; break; case 20: atom->ul = stats->client.req_control; break; default: return PM_ERR_PMID; } return 0; } static int fill_timeout(unsigned int item, pmAtomValue *atom) { switch (item) { case 21: atom->ul = stats->timeouts.call; break; case 22: atom->ul = stats->timeouts.control; break; case 23: atom->ul = stats->timeouts.traverse; break; default: return PM_ERR_PMID; } return 0; } /* * callback provided to pmdaFetch */ static int pmda_ctdb_fetch_cb(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { int ret; __pmID_int *id = (__pmID_int *)&(mdesc->m_desc.pmid); if (inst != PM_IN_NULL) { return PM_ERR_INST; } if (stats == NULL) { fprintf(stderr, "stats not available\n"); ret = PM_ERR_VALUE; goto err_out; } switch (id->cluster) { case 0: atom->ul = stats->num_clients; break; case 1: atom->ul = stats->frozen; break; case 3: atom->ul = stats->recovering; break; case 4: atom->ul = stats->client_packets_sent; break; case 5: atom->ul = stats->client_packets_recv; break; case 6: atom->ul = stats->node_packets_sent; break; case 7: atom->ul = stats->node_packets_recv; break; case 8: atom->ul = stats->keepalive_packets_sent; break; case 9: atom->ul = stats->keepalive_packets_recv; break; case 10: ret = fill_node(id->item, atom); if (ret) { goto err_out; } break; case 11: ret = fill_client(id->item, atom); if (ret) { goto err_out; } break; case 12: ret = fill_timeout(id->item, atom); if (ret) { goto err_out; } break; case 13: atom->ul = stats->total_calls; break; case 14: atom->ul = stats->pending_calls; break; case 15: atom->ul = stats->locks.num_calls; break; case 16: atom->ul = stats->locks.num_pending; break; case 17: atom->ul = stats->childwrite_calls; break; case 18: atom->ul = stats->pending_childwrite_calls; break; case 19: atom->ul = stats->memory_used; break; case 20: atom->ul = stats->max_hop_count; break; case 21: atom->d = stats->reclock.ctdbd.max; break; case 22: atom->d = stats->reclock.recd.max; break; case 23: atom->d = stats->call_latency.max; break; case 24: atom->d = stats->locks.latency.max; break; case 25: atom->d = stats->childwrite_latency.max; break; case 26: atom->d = stats->num_recoveries; break; default: return PM_ERR_PMID; } ret = 0; err_out: return ret; } /* * This routine is called once for each pmFetch(3) operation, so is a * good place to do once-per-fetch functions, such as value caching or * instance domain evaluation. */ static int pmda_ctdb_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int ret; TDB_DATA data; int32_t res; struct timeval ctdb_timeout; if (ctdb == NULL) { fprintf(stderr, "attempting reconnect to ctdbd\n"); ret = pmda_ctdb_daemon_connect(); if (ret < 0) { fprintf(stderr, "reconnect failed\n"); return PM_ERR_VALUE; } } ctdb_timeout = timeval_current_ofs(1, 0); ret = ctdb_control(ctdb, ctdb->pnn, 0, CTDB_CONTROL_STATISTICS, 0, tdb_null, ctdb, &data, &res, &ctdb_timeout, NULL); if (ret != 0 || res != 0) { fprintf(stderr, "ctdb control for statistics failed, reconnecting\n"); pmda_ctdb_daemon_disconnect(); ret = PM_ERR_VALUE; goto err_out; } stats = (struct ctdb_statistics *)data.dptr; if (data.dsize != sizeof(struct ctdb_statistics)) { fprintf(stderr, "incorrect statistics size %zu - not %zu\n", data.dsize, sizeof(struct ctdb_statistics)); ret = PM_ERR_VALUE; goto err_stats; } ret = pmdaFetch(numpmid, pmidlist, resp, pmda); err_stats: talloc_free(stats); err_out: return ret; } /* * Initialise the agent */ void pmda_ctdb_init(pmdaInterface *dp) { if (dp->status != 0) { return; } dp->version.two.fetch = pmda_ctdb_fetch; pmdaSetFetchCallBack(dp, pmda_ctdb_fetch_cb); pmdaInit(dp, NULL, 0, metrictab, (sizeof(metrictab) / sizeof(metrictab[0]))); } static char * helpfile(void) { static char buf[MAXPATHLEN]; if (!buf[0]) { snprintf(buf, sizeof(buf), "%s/ctdb/help", pmGetConfig("PCP_PMDAS_DIR")); } return buf; } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" "\nExactly one of the following options may appear:\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int err = 0; char log_file[] = "pmda_ctdb.log"; pmdaInterface dispatch; __pmSetProgname(argv[0]); pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, CTDB, log_file, helpfile()); if (pmdaGetOpt(argc, argv, "d:i:l:pu:?", &dispatch, &err) != EOF) { err++; } if (err) { usage(); } pmdaOpenLog(&dispatch); pmda_ctdb_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } ctdb-2.5.1.dfsg/utils/pmda/pmns0000644000175000017500000000354012245023514016210 0ustar mathieumathieu/* * Metrics for CTDB PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2011 David Disseldorp * * This program 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 of the License, or (at your * option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ ctdb { num_clients CTDB:0:0 frozen CTDB:0:1 recovering CTDB:0:2 client_packets_sent CTDB:0:3 client_packets_recv CTDB:0:4 node_packets_sent CTDB:0:5 node_packets_recv CTDB:0:6 keepalive_packets_sent CTDB:0:7 keepalive_packets_recv CTDB:0:8 node client timeouts total_calls CTDB:0:9 pending_calls CTDB:0:10 lockwait_calls CTDB:0:11 pending_lockwait_calls CTDB:0:12 childwrite_calls CTDB:0:13 pending_childwrite_calls CTDB:0:14 memory_used CTDB:0:15 max_hop_count CTDB:0:16 max_reclock_ctdbd CTDB:0:17 max_reclock_recd CTDB:0:18 max_call_latency CTDB:0:19 max_lockwait_latency CTDB:0:20 max_childwrite_latency CTDB:0:21 num_recoveries CTDB:0:22 } ctdb.node { req_call CTDB:1:0 reply_call CTDB:1:1 req_dmaster CTDB:1:2 reply_dmaster CTDB:1:3 reply_error CTDB:1:4 req_message CTDB:1:5 req_control CTDB:1:6 reply_control CTDB:1:7 } ctdb.client { req_call CTDB:2:0 req_message CTDB:2:1 req_control CTDB:2:2 } ctdb.timeouts { call CTDB:3:0 control CTDB:3:1 traverse CTDB:3:2 } ctdb-2.5.1.dfsg/utils/pmda/Remove0000644000175000017500000000160712245023514016472 0ustar mathieumathieu#! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program 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 of the License, or (at your # option) any later version. # # This program 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 this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Remove the ctdb PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=ctdb pmdaSetup pmdaRemove exit 0 ctdb-2.5.1.dfsg/utils/pmda/Install0000644000175000017500000000202012245023514016631 0ustar mathieumathieu#! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program 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 of the License, or (at your # option) any later version. # # This program 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 this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Install the ctdb PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=ctdb pmda_interface=2 # runs as daemon and only supports pipe IPC daemon_opt=true dso_opt=false pipe_opt=true socket_opt=false pmdaSetup pmdaInstall exit 0 ctdb-2.5.1.dfsg/utils/pmda/help0000644000175000017500000000744412245023514016172 0ustar mathieumathieu# # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program 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 of the License, or (at your # option) any later version. # # This program 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 this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # ctdb PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ ctdb.num_clients number of clients connected to ctdbd @ ctdb.frozen whether any databases are frozen @ ctdb.recovering whether recovery is active @ ctdb.client_packets_sent number of packets sent to all clients @ ctdb.client_packets_recv number of packets received from all clients @ ctdb.node_packets_sent number of packets sent to other nodes @ ctdb.node_packets_recv number of packets received from other nodes @ ctdb.keepalive_packets_sent number of keepalive packets sent to other nodes @ ctdb.keepalive_packets_recv number of keepalive packets received from other nodes @ ctdb.node.req_call number of node CTDB_REQ_CALL packets handled @ ctdb.node.reply_call number of node CTDB_REPLY_CALL packets handled @ ctdb.node.req_dmaster number of node CTDB_REQ_DMASTER packets handled @ ctdb.node.reply_dmaster number of node CTDB_REPLY_DMASTER packets handled @ ctdb.node.reply_error number of node CTDB_REPLY_ERROR packets handled @ ctdb.node.req_message number of node CTDB_REQ_MESSAGE packets handled @ ctdb.node.req_control number of node CTDB_REQ_CONTROL packets handled @ ctdb.node.reply_control number of node CTDB_REPLY_CONTROL packets handled @ ctdb.client.req_call number of client CTDB_REQ_CALL packets handled @ ctdb.client.req_message number of client CTDB_REQ_MESSAGE packets handled @ ctdb.client.req_control number of client CTDB_REQ_CONTROL packets handled @ ctdb.timeouts.call (counter not implemented) number of call timeouts @ ctdb.timeouts.control number of node control message request timeouts awaiting reply @ ctdb.timeouts.traverse number of database traversal timeouts @ ctdb.total_calls total number of client ctdb request calls received @ ctdb.pending_calls total number of client ctdb request calls in progress @ ctdb.lockwait_calls number of tdb chainlock lockwait calls @ ctdb.pending_lockwait_calls number of lockwait calls waiting for a lock @ ctdb.childwrite_calls number of childwrite calls @ ctdb.pending_childwrite_calls number of childwrite calls in progress @ ctdb.memory_used total size of the ctdbd null talloc pool @ ctdb.max_hop_count maximum hops performed by a CTDB_REQ_CALL packet @ ctdb.max_reclock_ctdbd maximum recovery lock latency during setrecmode @ ctdb.max_reclock_recd maximum recovery lock latency as reported by the recovery process @ ctdb.max_call_latency maximum time spent handling a client request call @ ctdb.max_lockwait_latency maximum time spent waiting for a tdb chainlock @ ctdb.max_childwrite_latency maximum time spent performing a childwrite @ ctdb.num_recoveries number of recoveries finished ctdb-2.5.1.dfsg/utils/nagios/0000755000175000017500000000000012245023514015645 5ustar mathieumathieuctdb-2.5.1.dfsg/utils/nagios/README0000644000175000017500000000343612245023514016533 0ustar mathieumathieucheck_ctdb 0.3 This nagios plugin is free software, and comes with ABSOLUTELY NO WARRANTY. It may be used, redistributed and/or modified under the terms of the GNU General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt). CTDB plugin Usage: check_ctdb -i [ -t ] [ -w ] [ -c ] [ -H ] [-s] [ -l ] [ -V ] [ -h ] -?, --usage Print usage information -h, --help Print detailed help screen -V, --version Print version information --extra-opts=[section][@file] Read options from an ini file. See http://nagiosplugins.org/extra-opts for usage -i, --info= Information: One of scriptstatus or ping. -H, --hostname= Host name or IP Address. -s, --sudo Use sudo. -l, --login= The user to log in as on the remote machine. -w, --warning=THRESHOLD Warning threshold. See http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT for the threshold format. -c, --critical=THRESHOLD Critical threshold. See http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT for the threshold format. -t, --timeout=INTEGER Seconds before plugin times out (default: 30) -v, --verbose Show details for command-line debugging (can repeat up to 3 times) Supported commands: * scriptstatus : check the ctdb scriptstatus command and return CRITICAL if one of the scripts fails. Perfdata count the number of scripts by state (ok, disabled, error, total). * ping : check the ctdb ping command. Perfdata count the number of nodes, the total ping time and the number of clients. Thresholds are checked against the number of nodes. Copyright (c) 2011 Nantes Metropole ctdb-2.5.1.dfsg/utils/nagios/check_ctdb0000644000175000017500000002134012245023514017641 0ustar mathieumathieu#!/usr/bin/perl -w # Nagios plugin to monitor CTDB (Clustered Trivial Database) # # License: GPL # Copyright (c) 2011 Nantes Metropole # Author: Mathieu Parent # Contributor(s): - # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program 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 this program. If not, see . # use strict; use warnings; use vars qw($PROGNAME $VERSION $output $values $result); use Nagios::Plugin; use File::Basename; $PROGNAME = basename($0); $VERSION = '0.4'; my $np = Nagios::Plugin->new( usage => "Usage: %s -i \n" . " [ -t ] [ -w ] [ -c ]\n" . " [ -H ] [-s] [ -l ]\n" . ' [ -V ] [ -h ]', version => $VERSION, plugin => $PROGNAME, shortname => uc($PROGNAME), blurb => 'CTDB plugin', extra => "Supported commands:\n" . " * scriptstatus :\n" . " check the ctdb scriptstatus command and return CRITICAL if one of the\n" . " scripts fails.\n" . " Perfdata count the number of scripts by state (ok, disabled, error,\n" . " total).\n" . " * ping :\n" . " check the ctdb ping command.\n" . " Perfdata count the number of nodes, the total ping time and the number\n" . " of clients.\n" . " Thresholds are checked against the number of nodes.\n" . "\n\nCopyright (c) 2011 Nantes Metropole", timeout => 30, ); $np->add_arg( spec => 'info|i=s', help => "-i, --info=\n" . ' Information: One of scriptstatus or ping.', required => 1, ); $np->add_arg( spec => 'hostname|H=s', help => "-H, --hostname=\n" . ' Host name or IP Address.', required => 0, ); $np->add_arg( spec => 'sudo|s', help => "-s, --sudo\n" . ' Use sudo.', required => 0, ); $np->add_arg( spec => 'login|l=s', help => "-l, --login=\n" . ' The user to log in as on the remote machine.', required => 0, ); $np->add_arg( spec => 'warning|w=s', help => "-w, --warning=THRESHOLD\n" . " Warning threshold. See\n" . " http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT\n" . ' for the threshold format.', required => 0, ); $np->add_arg( spec => 'critical|c=s', help => "-c, --critical=THRESHOLD\n" . " Critical threshold. See\n" . " http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT\n" . ' for the threshold format.', required => 0, ); $np->getopts; my $info = $np->opts->info; my $hostname = $np->opts->hostname; my $login = $np->opts->login; my $sudo = $np->opts->sudo; my $warning = $np->opts->warning; my $critical = $np->opts->critical; my $percw; my $percc; $output = ""; if (defined($critical)) { ($percc, $critical) = check_percantage($critical); $critical = undef if ($critical eq ''); } if (defined($warning)) { ($percw, $warning) = check_percantage($warning); $warning = undef if ($warning eq ''); } $np->set_thresholds(critical => $critical, warning => $warning); my $stderr; sub safe_open_command { unshift @_, "sudo" if $sudo; if ($hostname) { unshift @_, $hostname; unshift @_, "-l", $login if $login; unshift @_, "ssh"; } open(OLDERR, ">&", \*STDERR) or die "Can't dup STDERR: $!"; $stderr = ""; close STDERR; open(STDERR, ">>", \$stderr) or die "Can't open STDERR: $!"; if ($np->opts->verbose) { print "Executing: @_\n"; } if (!open(PIPE, '-|', @_)) { $result = CRITICAL; $output .= "Cannot open command '@_': $! ($stderr). "; # restore STDERR open(STDERR, ">", \*OLDERR) or die "Can't dup OLDERR: $!"; } } sub safe_close_command { close(PIPE); if ($? == -1) { $result = CRITICAL; $output .= "failed to execute: $!. "; } elsif ($? & 127) { $result = CRITICAL; $output .= sprintf("child died with signal %d, %s coredump. ", ($? & 127), ($? & 128) ? 'with' : 'without'); } elsif ($? >> 8) { if (($? >> 8) == 255) { # ctdb returns -1=255 if any node is disconnected $result = WARNING; $output .= sprintf("child exited with value %d. ", $? >> 8) if $output eq ""; } else { $result = CRITICAL; $output .= sprintf("child exited with value %d. ", $? >> 8); } } # restore STDERR open(STDERR, ">&OLDERR") or die "Can't dup OLDERR: $!"; } # main : if ($info eq "scriptstatus") { $result = OK; safe_open_command('ctdb', '-Y', 'scriptstatus'); if ($result == OK) { my $script_count = 0; my $ok_script_count = 0; my $disabled_script_count = 0; my $error_script_count = 0; while () { next if $. == 1; # Header $script_count++; chop; my ($col0, $type, $name, $code, $status, $start, $end, @error) = split(":"); if ($col0 ne '') { # Old version, before 30 Aug 2011 and commit a779d83a6213 ($type, $name, $code, $status, $start, $end, @error) = ($col0, $type, $name, $code, $status, $start, $end, @error); } my $error = join(':', @error); if ($error ne "") { $output = "$output ;; " if $output; $output = "$output$name ($status=$code): $error "; if ($result != CRITICAL) { $result = WARNING; } } if ($status eq "OK") { $ok_script_count++; next; } if ($status eq "DISABLED") { $disabled_script_count++; next; } $error_script_count++; $result = WARNING; } safe_close_command(); $np->add_perfdata(label => "ok", value => $ok_script_count, uom => '', min => 0, max => $script_count); $np->add_perfdata(label => "disabled", value => $disabled_script_count, uom => '', min => 0, max => $script_count); $np->add_perfdata(label => "error", value => $error_script_count, uom => '', min => 0, max => $script_count, warning => '0', critical => '0'); $np->add_perfdata(label => "total", value => $script_count, uom => '', min => 0, max => $script_count); if ($result == OK) { $result = $np->check_threshold(check => $error_script_count, warning => '0', critical => '0'); } } $np->nagios_exit($result, $output); } elsif ($info eq "ping") { # Get expected nodes count $result = OK; safe_open_command('cat', '/etc/ctdb/nodes'); 1 while( ); my $max_nodes_count = $.; safe_close_command(); # ctdb ping $result = OK; safe_open_command('ctdb', '-n', 'all', 'ping'); if ($result == OK) { my $nodes_count = 0; my $time_total = 0.0; my $clients_count = 0; while () { chop; if ($_ =~ /^response from (\d+) time=([0-9.]+) sec \((\d+) clients\)$/) { my ($node_id, $time, $clients) = ($1,$2,$3); $nodes_count += 1; $time_total += $time; $clients_count += $clients; } elsif ($_ =~ /^Unable to get ping response from node (\d+)$/) { # } else { $result = CRITICAL; $output .= "'$_' doesn't match regexp. " } } $output .= sprintf("%d missing nodes. ", $max_nodes_count - $nodes_count) if $nodes_count < $max_nodes_count; safe_close_command(); $np->add_perfdata(label => "nodes", value => $nodes_count, uom => '', min => 0, max => $max_nodes_count, warning => $warning, critical => $critical); $np->add_perfdata(label => "ping_time", value => $time_total, uom => 's', min => 0, max => undef); $np->add_perfdata(label => "clients", value => $clients_count, uom => '', min => 0, max => undef); if ($result == OK) { $result = $np->check_threshold(check => $nodes_count); } } $np->nagios_exit($result, $output); } else { $np->nagios_exit(UNKNOWN, "Unknown command: '$info'"); } sub check_percantage { my ($number) = shift(@_); my $perc = $number =~ s/\%//; return ($perc, $number); } ctdb-2.5.1.dfsg/configure.ac0000644000175000017500000000651412245023514015521 0ustar mathieumathieuAC_PREREQ(2.50) AC_INIT(ctdb, m4_esyscmd([grep 'Version:' ./packaging/RPM/ctdb.spec 2>/dev/null | head -1 | sed -e 's/[ \t]*Version:[ \t]*\([^ \t]*\)[ \t]*.*/\1/' | tr -d '\n'])) AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""]) AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""]) AC_DEFUN([SMB_EXT_LIB], [echo -n ""]) AC_DEFUN([SMB_ENABLE], [echo -n ""]) AC_CONFIG_SRCDIR([server/ctdbd.c]) if test "${libdir}" = '${exec_prefix}/lib'; then case `uname -m` in x86_64|ppc64|powerpc64) libdir='${exec_prefix}/lib64' ;; *) libdir='${exec_prefix}/lib' ;; esac fi case `uname` in Linux*) CTDB_SYSTEM_OBJ=common/system_linux.o CTDB_SCSI_IO=bin/scsi_io CTDB_PCAP_LDFLAGS= ;; AIX*) CTDB_SYSTEM_OBJ=common/system_aix.o CTDB_SCSI_IO= CPPFLAGS="$CPPFLAGS -D_AIX_=1" CTDB_PCAP_LDFLAGS=-lpcap ;; GNU/kFreeBSD) CTDB_SYSTEM_OBJ=common/system_kfreebsd.o CTDB_SCSI_IO= CTDB_PCAP_LDFLAGS=-lpcap ;; FreeBSD) CTDB_SYSTEM_OBJ=common/system_freebsd.o CTDB_SCSI_IO= CTDB_PCAP_LDFLAGS=-lpcap LDFLAGS="$LDFLAGS -L/usr/local/lib -lexecinfo" AC_SUBST(LDFLAGS) CPPFLAGS="$CPPFLAGS -I/usr/local/include -D_FREEBSD_=1" AC_SUBST(CPPFLAGS) ;; GNU) CTDB_SYSTEM_OBJ=common/system_gnu.o CTDB_SCSI_IO= CTDB_PCAP_LDFLAGS=-lpcap ;; *) echo unknown system cant configure exit ;; esac AC_LIBREPLACE_ALL_CHECKS AC_LIBREPLACE_NETWORK_CHECKS if test "$ac_cv_prog_gcc" = yes; then CFLAGS="$CFLAGS -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings" fi LOGDIR='${localstatedir}/log' AC_ARG_WITH([logdir], [ --with-logdir=DIR path to log directory [[LOCALSTATEDIR/log]]], LOGDIR=$withval) if test ! -z "$LOGDIR"; then if test "$LOGDIR" = "yes" -o "$LOGDIR" = "no"; then AC_MSG_ERROR([--with-logdir must specify a path]) fi fi AC_SUBST(LOGDIR) SOCKPATH='${localstatedir}/run/ctdb/ctdbd.socket' AC_ARG_WITH([socketpath], [ --with-socketpath=FILE path to CTDB daemon socket [[LOCALSTATEDIR/run/ctdb/ctdbd.socket]]], SOCKPATH=$withval) if test ! -z "$SOCKPATH"; then if test "$SOCKPATH" = "yes" -o "$SOCKPATH" = "no"; then AC_MSG_ERROR([--with-socketpath must specify a file path]) fi fi AC_SUBST(SOCKPATH) AC_CONFIG_HEADER(config.h) EXTRA_OBJ="" m4_include(libpopt.m4) m4_include(libtalloc.m4) m4_include(libtdb.m4) m4_include(libtevent.m4) m4_include(ib/config.m4) m4_include(lib/util/signal.m4) m4_include(lib/util/fault.m4) m4_include(lib/socket_wrapper/config.m4) m4_include(utils/pmda/config.m4) AC_CHECK_HEADERS(sched.h) AC_CHECK_HEADERS(procinfo.h) AC_CHECK_DECL([ETIME], [],[AC_DEFINE([ETIME], ETIMEDOUT, [ETIME on non-supporting platforms])], [ #include ]) AC_CHECK_FUNCS(sched_setscheduler) AC_CHECK_FUNCS(thread_setsched) AC_CHECK_FUNCS(mlockall) AC_CACHE_CHECK([for sin_len in sock],ctdb_cv_HAVE_SOCK_SIN_LEN,[ AC_TRY_COMPILE([#include #include #include ], [struct sockaddr_in sock; sock.sin_len = sizeof(sock);], ctdb_cv_HAVE_SOCK_SIN_LEN=yes,ctdb_cv_HAVE_SOCK_SIN_LEN=no)]) if test x"$ctdb_cv_HAVE_SOCK_SIN_LEN" = x"yes"; then AC_DEFINE(HAVE_SOCK_SIN_LEN,1,[Whether the sockaddr_in struct has a sin_len property]) fi AC_SUBST(EXTRA_OBJ) AC_SUBST(CTDB_SYSTEM_OBJ) AC_SUBST(CTDB_SCSI_IO) AC_SUBST(CTDB_PCAP_LDFLAGS) AC_OUTPUT(Makefile ctdb.pc) ctdb-2.5.1.dfsg/client/0000755000175000017500000000000012245023514014503 5ustar mathieumathieuctdb-2.5.1.dfsg/client/ctdb_client.c0000644000175000017500000035357412245023514017142 0ustar mathieumathieu/* ctdb daemon code Copyright (C) Andrew Tridgell 2007 Copyright (C) Ronnie Sahlberg 2007 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #include "includes.h" #include "db_wrap.h" #include "tdb.h" #include "lib/util/dlinklist.h" #include "system/network.h" #include "system/filesys.h" #include "system/locale.h" #include #include "../include/ctdb_private.h" #include "lib/util/dlinklist.h" pid_t ctdbd_pid; /* allocate a packet for use in client<->daemon communication */ struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, enum ctdb_operation operation, size_t length, size_t slength, const char *type) { int size; struct ctdb_req_header *hdr; length = MAX(length, slength); size = (length+(CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1); hdr = (struct ctdb_req_header *)talloc_zero_size(mem_ctx, size); if (hdr == NULL) { DEBUG(DEBUG_ERR,("Unable to allocate packet for operation %u of length %u\n", operation, (unsigned)length)); return NULL; } talloc_set_name_const(hdr, type); hdr->length = length; hdr->operation = operation; hdr->ctdb_magic = CTDB_MAGIC; hdr->ctdb_version = CTDB_VERSION; hdr->srcnode = ctdb->pnn; if (ctdb->vnn_map) { hdr->generation = ctdb->vnn_map->generation; } return hdr; } /* local version of ctdb_call */ int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call, struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx, TDB_DATA *data, bool updatetdb) { struct ctdb_call_info *c; struct ctdb_registered_call *fn; struct ctdb_context *ctdb = ctdb_db->ctdb; c = talloc(ctdb, struct ctdb_call_info); CTDB_NO_MEMORY(ctdb, c); c->key = call->key; c->call_data = &call->call_data; c->record_data.dptr = talloc_memdup(c, data->dptr, data->dsize); c->record_data.dsize = data->dsize; CTDB_NO_MEMORY(ctdb, c->record_data.dptr); c->new_data = NULL; c->reply_data = NULL; c->status = 0; c->header = header; for (fn=ctdb_db->calls;fn;fn=fn->next) { if (fn->id == call->call_id) break; } if (fn == NULL) { ctdb_set_error(ctdb, "Unknown call id %u\n", call->call_id); talloc_free(c); return -1; } if (fn->fn(c) != 0) { ctdb_set_error(ctdb, "ctdb_call %u failed\n", call->call_id); talloc_free(c); return -1; } /* we need to force the record to be written out if this was a remote access */ if (c->new_data == NULL) { c->new_data = &c->record_data; } if (c->new_data && updatetdb) { /* XXX check that we always have the lock here? */ if (ctdb_ltdb_store(ctdb_db, call->key, header, *c->new_data) != 0) { ctdb_set_error(ctdb, "ctdb_call tdb_store failed\n"); talloc_free(c); return -1; } } if (c->reply_data) { call->reply_data = *c->reply_data; talloc_steal(call, call->reply_data.dptr); talloc_set_name_const(call->reply_data.dptr, __location__); } else { call->reply_data.dptr = NULL; call->reply_data.dsize = 0; } call->status = c->status; talloc_free(c); return 0; } /* queue a packet for sending from client to daemon */ static int ctdb_client_queue_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { return ctdb_queue_send(ctdb->daemon.queue, (uint8_t *)hdr, hdr->length); } /* called when a CTDB_REPLY_CALL packet comes in in the client This packet comes in response to a CTDB_REQ_CALL request packet. It contains any reply data from the call */ static void ctdb_client_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_reply_call *c = (struct ctdb_reply_call *)hdr; struct ctdb_client_call_state *state; state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_call_state); if (state == NULL) { DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid)); return; } if (hdr->reqid != state->reqid) { /* we found a record but it was the wrong one */ DEBUG(DEBUG_ERR, ("Dropped client call reply with reqid:%u\n",hdr->reqid)); return; } state->call->reply_data.dptr = c->data; state->call->reply_data.dsize = c->datalen; state->call->status = c->status; talloc_steal(state, c); state->state = CTDB_CALL_DONE; if (state->async.fn) { state->async.fn(state); } } static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); /* this is called in the client, when data comes in from the daemon */ void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args) { struct ctdb_context *ctdb = talloc_get_type(args, struct ctdb_context); struct ctdb_req_header *hdr = (struct ctdb_req_header *)data; TALLOC_CTX *tmp_ctx; /* place the packet as a child of a tmp_ctx. We then use talloc_free() below to free it. If any of the calls want to keep it, then they will steal it somewhere else, and the talloc_free() will be a no-op */ tmp_ctx = talloc_new(ctdb); talloc_steal(tmp_ctx, hdr); if (cnt == 0) { DEBUG(DEBUG_CRIT,("Daemon has exited - shutting down client\n")); exit(1); } if (cnt < sizeof(*hdr)) { DEBUG(DEBUG_CRIT,("Bad packet length %u in client\n", (unsigned)cnt)); goto done; } if (cnt != hdr->length) { ctdb_set_error(ctdb, "Bad header length %u expected %u in client\n", (unsigned)hdr->length, (unsigned)cnt); goto done; } if (hdr->ctdb_magic != CTDB_MAGIC) { ctdb_set_error(ctdb, "Non CTDB packet rejected in client\n"); goto done; } if (hdr->ctdb_version != CTDB_VERSION) { ctdb_set_error(ctdb, "Bad CTDB version 0x%x rejected in client\n", hdr->ctdb_version); goto done; } switch (hdr->operation) { case CTDB_REPLY_CALL: ctdb_client_reply_call(ctdb, hdr); break; case CTDB_REQ_MESSAGE: ctdb_request_message(ctdb, hdr); break; case CTDB_REPLY_CONTROL: ctdb_client_reply_control(ctdb, hdr); break; default: DEBUG(DEBUG_CRIT,("bogus operation code:%u\n",hdr->operation)); } done: talloc_free(tmp_ctx); } /* connect to a unix domain socket */ int ctdb_socket_connect(struct ctdb_context *ctdb) { struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, ctdb->daemon.name, sizeof(addr.sun_path)-1); ctdb->daemon.sd = socket(AF_UNIX, SOCK_STREAM, 0); if (ctdb->daemon.sd == -1) { DEBUG(DEBUG_ERR,(__location__ " Failed to open client socket. Errno:%s(%d)\n", strerror(errno), errno)); return -1; } if (connect(ctdb->daemon.sd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { close(ctdb->daemon.sd); ctdb->daemon.sd = -1; DEBUG(DEBUG_ERR,(__location__ " Failed to connect client socket to daemon. Errno:%s(%d)\n", strerror(errno), errno)); return -1; } set_nonblocking(ctdb->daemon.sd); set_close_on_exec(ctdb->daemon.sd); ctdb->daemon.queue = ctdb_queue_setup(ctdb, ctdb, ctdb->daemon.sd, CTDB_DS_ALIGNMENT, ctdb_client_read_cb, ctdb, "to-ctdbd"); return 0; } struct ctdb_record_handle { struct ctdb_db_context *ctdb_db; TDB_DATA key; TDB_DATA *data; struct ctdb_ltdb_header header; }; /* make a recv call to the local ctdb daemon - called from client context This is called when the program wants to wait for a ctdb_call to complete and get the results. This call will block unless the call has already completed. */ int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call) { if (state == NULL) { return -1; } while (state->state < CTDB_CALL_DONE) { event_loop_once(state->ctdb_db->ctdb->ev); } if (state->state != CTDB_CALL_DONE) { DEBUG(DEBUG_ERR,(__location__ " ctdb_call_recv failed\n")); talloc_free(state); return -1; } if (state->call->reply_data.dsize) { call->reply_data.dptr = talloc_memdup(state->ctdb_db, state->call->reply_data.dptr, state->call->reply_data.dsize); call->reply_data.dsize = state->call->reply_data.dsize; } else { call->reply_data.dptr = NULL; call->reply_data.dsize = 0; } call->status = state->call->status; talloc_free(state); return call->status; } /* destroy a ctdb_call in client */ static int ctdb_client_call_destructor(struct ctdb_client_call_state *state) { ctdb_reqid_remove(state->ctdb_db->ctdb, state->reqid); return 0; } /* construct an event driven local ctdb_call this is used so that locally processed ctdb_call requests are processed in an event driven manner */ static struct ctdb_client_call_state *ctdb_client_call_local_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call, struct ctdb_ltdb_header *header, TDB_DATA *data) { struct ctdb_client_call_state *state; struct ctdb_context *ctdb = ctdb_db->ctdb; int ret; state = talloc_zero(ctdb_db, struct ctdb_client_call_state); CTDB_NO_MEMORY_NULL(ctdb, state); state->call = talloc_zero(state, struct ctdb_call); CTDB_NO_MEMORY_NULL(ctdb, state->call); talloc_steal(state, data->dptr); state->state = CTDB_CALL_DONE; *(state->call) = *call; state->ctdb_db = ctdb_db; ret = ctdb_call_local(ctdb_db, state->call, header, state, data, true); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_call_local() failed, ignoring return code %d\n", ret)); } return state; } /* make a ctdb call to the local daemon - async send. Called from client context. This constructs a ctdb_call request and queues it for processing. This call never blocks. */ struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call) { struct ctdb_client_call_state *state; struct ctdb_context *ctdb = ctdb_db->ctdb; struct ctdb_ltdb_header header; TDB_DATA data; int ret; size_t len; struct ctdb_req_call *c; /* if the domain socket is not yet open, open it */ if (ctdb->daemon.sd==-1) { ctdb_socket_connect(ctdb); } ret = ctdb_ltdb_lock(ctdb_db, call->key); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " Failed to get chainlock\n")); return NULL; } ret = ctdb_ltdb_fetch(ctdb_db, call->key, &header, ctdb_db, &data); if ((call->flags & CTDB_IMMEDIATE_MIGRATION) && (header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) { ret = -1; } if (ret == 0 && header.dmaster == ctdb->pnn) { state = ctdb_client_call_local_send(ctdb_db, call, &header, &data); talloc_free(data.dptr); ctdb_ltdb_unlock(ctdb_db, call->key); return state; } ctdb_ltdb_unlock(ctdb_db, call->key); talloc_free(data.dptr); state = talloc_zero(ctdb_db, struct ctdb_client_call_state); if (state == NULL) { DEBUG(DEBUG_ERR, (__location__ " failed to allocate state\n")); return NULL; } state->call = talloc_zero(state, struct ctdb_call); if (state->call == NULL) { DEBUG(DEBUG_ERR, (__location__ " failed to allocate state->call\n")); return NULL; } len = offsetof(struct ctdb_req_call, data) + call->key.dsize + call->call_data.dsize; c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CALL, len, struct ctdb_req_call); if (c == NULL) { DEBUG(DEBUG_ERR, (__location__ " failed to allocate packet\n")); return NULL; } state->reqid = ctdb_reqid_new(ctdb, state); state->ctdb_db = ctdb_db; talloc_set_destructor(state, ctdb_client_call_destructor); c->hdr.reqid = state->reqid; c->flags = call->flags; c->db_id = ctdb_db->db_id; c->callid = call->call_id; c->hopcount = 0; c->keylen = call->key.dsize; c->calldatalen = call->call_data.dsize; memcpy(&c->data[0], call->key.dptr, call->key.dsize); memcpy(&c->data[call->key.dsize], call->call_data.dptr, call->call_data.dsize); *(state->call) = *call; state->call->call_data.dptr = &c->data[call->key.dsize]; state->call->key.dptr = &c->data[0]; state->state = CTDB_CALL_WAIT; ctdb_client_queue_pkt(ctdb, &c->hdr); return state; } /* full ctdb_call. Equivalent to a ctdb_call_send() followed by a ctdb_call_recv() */ int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call) { struct ctdb_client_call_state *state; state = ctdb_call_send(ctdb_db, call); return ctdb_call_recv(state, call); } /* tell the daemon what messaging srvid we will use, and register the message handler function in the client */ int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, ctdb_msg_fn_t handler, void *private_data) { int res; int32_t status; res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_REGISTER_SRVID, 0, tdb_null, NULL, NULL, &status, NULL, NULL); if (res != 0 || status != 0) { DEBUG(DEBUG_ERR,("Failed to register srvid %llu\n", (unsigned long long)srvid)); return -1; } /* also need to register the handler with our own ctdb structure */ return ctdb_register_message_handler(ctdb, ctdb, srvid, handler, private_data); } /* tell the daemon we no longer want a srvid */ int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data) { int res; int32_t status; res = ctdb_control(ctdb, CTDB_CURRENT_NODE, srvid, CTDB_CONTROL_DEREGISTER_SRVID, 0, tdb_null, NULL, NULL, &status, NULL, NULL); if (res != 0 || status != 0) { DEBUG(DEBUG_ERR,("Failed to deregister srvid %llu\n", (unsigned long long)srvid)); return -1; } /* also need to register the handler with our own ctdb structure */ ctdb_deregister_message_handler(ctdb, srvid, private_data); return 0; } /* * check server ids */ int ctdb_client_check_message_handlers(struct ctdb_context *ctdb, uint64_t *ids, uint32_t num, uint8_t *result) { TDB_DATA indata, outdata; int res; int32_t status; int i; indata.dptr = (uint8_t *)ids; indata.dsize = num * sizeof(*ids); res = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_CHECK_SRVIDS, 0, indata, ctdb, &outdata, &status, NULL, NULL); if (res != 0 || status != 0) { DEBUG(DEBUG_ERR, (__location__ " failed to check srvids\n")); return -1; } if (outdata.dsize != num*sizeof(uint8_t)) { DEBUG(DEBUG_ERR, (__location__ " expected %lu bytes, received %zi bytes\n", (long unsigned int)num*sizeof(uint8_t), outdata.dsize)); talloc_free(outdata.dptr); return -1; } for (i=0; ihdr.destnode = pnn; r->srvid = srvid; r->datalen = data.dsize; memcpy(&r->data[0], data.dptr, data.dsize); res = ctdb_client_queue_pkt(ctdb, &r->hdr); talloc_free(r); return res; } /* cancel a ctdb_fetch_lock operation, releasing the lock */ static int fetch_lock_destructor(struct ctdb_record_handle *h) { ctdb_ltdb_unlock(h->ctdb_db, h->key); return 0; } /* force the migration of a record to this node */ static int ctdb_client_force_migration(struct ctdb_db_context *ctdb_db, TDB_DATA key) { struct ctdb_call call; ZERO_STRUCT(call); call.call_id = CTDB_NULL_FUNC; call.key = key; call.flags = CTDB_IMMEDIATE_MIGRATION; return ctdb_call(ctdb_db, &call); } /* try to fetch a readonly copy of a record */ static int ctdb_client_fetch_readonly(struct ctdb_db_context *ctdb_db, TDB_DATA key, TALLOC_CTX *mem_ctx, struct ctdb_ltdb_header **hdr, TDB_DATA *data) { int ret; struct ctdb_call call; ZERO_STRUCT(call); call.call_id = CTDB_FETCH_WITH_HEADER_FUNC; call.call_data.dptr = NULL; call.call_data.dsize = 0; call.key = key; call.flags = CTDB_WANT_READONLY; ret = ctdb_call(ctdb_db, &call); if (ret != 0) { return -1; } if (call.reply_data.dsize < sizeof(struct ctdb_ltdb_header)) { return -1; } *hdr = talloc_memdup(mem_ctx, &call.reply_data.dptr[0], sizeof(struct ctdb_ltdb_header)); if (*hdr == NULL) { talloc_free(call.reply_data.dptr); return -1; } data->dsize = call.reply_data.dsize - sizeof(struct ctdb_ltdb_header); data->dptr = talloc_memdup(mem_ctx, &call.reply_data.dptr[sizeof(struct ctdb_ltdb_header)], data->dsize); if (data->dptr == NULL) { talloc_free(call.reply_data.dptr); talloc_free(hdr); return -1; } return 0; } /* get a lock on a record, and return the records data. Blocks until it gets the lock */ struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data) { int ret; struct ctdb_record_handle *h; /* procedure is as follows: 1) get the chain lock. 2) check if we are dmaster 3) if we are the dmaster then return handle 4) if not dmaster then ask ctdb daemon to make us dmaster, and wait for reply from ctdbd 5) when we get the reply, goto (1) */ h = talloc_zero(mem_ctx, struct ctdb_record_handle); if (h == NULL) { return NULL; } h->ctdb_db = ctdb_db; h->key = key; h->key.dptr = talloc_memdup(h, key.dptr, key.dsize); if (h->key.dptr == NULL) { talloc_free(h); return NULL; } h->data = data; DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: key=%*.*s\n", (int)key.dsize, (int)key.dsize, (const char *)key.dptr)); again: /* step 1 - get the chain lock */ ret = ctdb_ltdb_lock(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " failed to lock ltdb record\n")); talloc_free(h); return NULL; } DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: got chain lock\n")); talloc_set_destructor(h, fetch_lock_destructor); ret = ctdb_ltdb_fetch(ctdb_db, key, &h->header, h, data); /* when torturing, ensure we test the remote path */ if ((ctdb_db->ctdb->flags & CTDB_FLAG_TORTURE) && random() % 5 == 0) { h->header.dmaster = (uint32_t)-1; } DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: done local fetch\n")); if (ret != 0 || h->header.dmaster != ctdb_db->ctdb->pnn) { ctdb_ltdb_unlock(ctdb_db, key); ret = ctdb_client_force_migration(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: force_migration failed\n")); talloc_free(h); return NULL; } goto again; } DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: we are dmaster - done\n")); return h; } /* get a readonly lock on a record, and return the records data. Blocks until it gets the lock */ struct ctdb_record_handle * ctdb_fetch_readonly_lock( struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data, int read_only) { int ret; struct ctdb_record_handle *h; struct ctdb_ltdb_header *roheader = NULL; h = talloc_zero(mem_ctx, struct ctdb_record_handle); if (h == NULL) { return NULL; } h->ctdb_db = ctdb_db; h->key = key; h->key.dptr = talloc_memdup(h, key.dptr, key.dsize); if (h->key.dptr == NULL) { talloc_free(h); return NULL; } h->data = data; data->dptr = NULL; data->dsize = 0; again: talloc_free(roheader); roheader = NULL; talloc_free(data->dptr); data->dptr = NULL; data->dsize = 0; /* Lock the record/chain */ ret = ctdb_ltdb_lock(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " failed to lock ltdb record\n")); talloc_free(h); return NULL; } talloc_set_destructor(h, fetch_lock_destructor); /* Check if record exists yet in the TDB */ ret = ctdb_ltdb_fetch_with_header(ctdb_db, key, &h->header, h, data); if (ret != 0) { ctdb_ltdb_unlock(ctdb_db, key); ret = ctdb_client_force_migration(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n")); talloc_free(h); return NULL; } goto again; } /* if this is a request for read/write and we have delegations we have to revoke all delegations first */ if ((read_only == 0) && (h->header.dmaster == ctdb_db->ctdb->pnn) && (h->header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) { ctdb_ltdb_unlock(ctdb_db, key); ret = ctdb_client_force_migration(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n")); talloc_free(h); return NULL; } goto again; } /* if we are dmaster, just return the handle */ if (h->header.dmaster == ctdb_db->ctdb->pnn) { return h; } if (read_only != 0) { TDB_DATA rodata = {NULL, 0}; if ((h->header.flags & CTDB_REC_RO_HAVE_READONLY) || (h->header.flags & CTDB_REC_RO_HAVE_DELEGATIONS)) { return h; } ctdb_ltdb_unlock(ctdb_db, key); ret = ctdb_client_fetch_readonly(ctdb_db, key, h, &roheader, &rodata); if (ret != 0) { DEBUG(DEBUG_ERR,("ctdb_fetch_readonly_lock: failed. force migration and try again\n")); ret = ctdb_client_force_migration(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n")); talloc_free(h); return NULL; } goto again; } if (!(roheader->flags&CTDB_REC_RO_HAVE_READONLY)) { ret = ctdb_client_force_migration(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n")); talloc_free(h); return NULL; } goto again; } ret = ctdb_ltdb_lock(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " failed to lock ltdb record\n")); talloc_free(h); return NULL; } ret = ctdb_ltdb_fetch_with_header(ctdb_db, key, &h->header, h, data); if (ret != 0) { ctdb_ltdb_unlock(ctdb_db, key); ret = ctdb_client_force_migration(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_fetch_readonly_lock: force_migration failed\n")); talloc_free(h); return NULL; } goto again; } return h; } /* we are not dmaster and this was not a request for a readonly lock * so unlock the record, migrate it and try again */ ctdb_ltdb_unlock(ctdb_db, key); ret = ctdb_client_force_migration(ctdb_db, key); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_fetch_lock: force_migration failed\n")); talloc_free(h); return NULL; } goto again; } /* store some data to the record that was locked with ctdb_fetch_lock() */ int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data) { if (h->ctdb_db->persistent) { DEBUG(DEBUG_ERR, (__location__ " ctdb_record_store prohibited for persistent dbs\n")); return -1; } return ctdb_ltdb_store(h->ctdb_db, h->key, &h->header, data); } /* non-locking fetch of a record */ int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data) { struct ctdb_call call; int ret; call.call_id = CTDB_FETCH_FUNC; call.call_data.dptr = NULL; call.call_data.dsize = 0; call.key = key; ret = ctdb_call(ctdb_db, &call); if (ret == 0) { *data = call.reply_data; talloc_steal(mem_ctx, data->dptr); } return ret; } /* called when a control completes or timesout to invoke the callback function the user provided */ static void invoke_control_callback(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data) { struct ctdb_client_control_state *state; TALLOC_CTX *tmp_ctx = talloc_new(NULL); int ret; state = talloc_get_type(private_data, struct ctdb_client_control_state); talloc_steal(tmp_ctx, state); ret = ctdb_control_recv(state->ctdb, state, state, NULL, NULL, NULL); if (ret != 0) { DEBUG(DEBUG_DEBUG,("ctdb_control_recv() failed, ignoring return code %d\n", ret)); } talloc_free(tmp_ctx); } /* called when a CTDB_REPLY_CONTROL packet comes in in the client This packet comes in response to a CTDB_REQ_CONTROL request packet. It contains any reply data from the control */ static void ctdb_client_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_reply_control *c = (struct ctdb_reply_control *)hdr; struct ctdb_client_control_state *state; state = ctdb_reqid_find(ctdb, hdr->reqid, struct ctdb_client_control_state); if (state == NULL) { DEBUG(DEBUG_ERR,(__location__ " reqid %u not found\n", hdr->reqid)); return; } if (hdr->reqid != state->reqid) { /* we found a record but it was the wrong one */ DEBUG(DEBUG_ERR, ("Dropped orphaned reply control with reqid:%u\n",hdr->reqid)); return; } state->outdata.dptr = c->data; state->outdata.dsize = c->datalen; state->status = c->status; if (c->errorlen) { state->errormsg = talloc_strndup(state, (char *)&c->data[c->datalen], c->errorlen); } /* state->outdata now uses resources from c so we dont want c to just dissappear from under us while state is still alive */ talloc_steal(state, c); state->state = CTDB_CONTROL_DONE; /* if we had a callback registered for this control, pull the response and call the callback. */ if (state->async.fn) { event_add_timed(ctdb->ev, state, timeval_zero(), invoke_control_callback, state); } } /* destroy a ctdb_control in client */ static int ctdb_client_control_destructor(struct ctdb_client_control_state *state) { ctdb_reqid_remove(state->ctdb, state->reqid); return 0; } /* time out handler for ctdb_control */ static void control_timeout_func(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data) { struct ctdb_client_control_state *state = talloc_get_type(private_data, struct ctdb_client_control_state); DEBUG(DEBUG_ERR,(__location__ " control timed out. reqid:%u opcode:%u " "dstnode:%u\n", state->reqid, state->c->opcode, state->c->hdr.destnode)); state->state = CTDB_CONTROL_TIMEOUT; /* if we had a callback registered for this control, pull the response and call the callback. */ if (state->async.fn) { event_add_timed(state->ctdb->ev, state, timeval_zero(), invoke_control_callback, state); } } /* async version of send control request */ struct ctdb_client_control_state *ctdb_control_send(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, uint32_t opcode, uint32_t flags, TDB_DATA data, TALLOC_CTX *mem_ctx, struct timeval *timeout, char **errormsg) { struct ctdb_client_control_state *state; size_t len; struct ctdb_req_control *c; int ret; if (errormsg) { *errormsg = NULL; } /* if the domain socket is not yet open, open it */ if (ctdb->daemon.sd==-1) { ctdb_socket_connect(ctdb); } state = talloc_zero(mem_ctx, struct ctdb_client_control_state); CTDB_NO_MEMORY_NULL(ctdb, state); state->ctdb = ctdb; state->reqid = ctdb_reqid_new(ctdb, state); state->state = CTDB_CONTROL_WAIT; state->errormsg = NULL; talloc_set_destructor(state, ctdb_client_control_destructor); len = offsetof(struct ctdb_req_control, data) + data.dsize; c = ctdbd_allocate_pkt(ctdb, state, CTDB_REQ_CONTROL, len, struct ctdb_req_control); state->c = c; CTDB_NO_MEMORY_NULL(ctdb, c); c->hdr.reqid = state->reqid; c->hdr.destnode = destnode; c->opcode = opcode; c->client_id = 0; c->flags = flags; c->srvid = srvid; c->datalen = data.dsize; if (data.dsize) { memcpy(&c->data[0], data.dptr, data.dsize); } /* timeout */ if (timeout && !timeval_is_zero(timeout)) { event_add_timed(ctdb->ev, state, *timeout, control_timeout_func, state); } ret = ctdb_client_queue_pkt(ctdb, &(c->hdr)); if (ret != 0) { talloc_free(state); return NULL; } if (flags & CTDB_CTRL_FLAG_NOREPLY) { talloc_free(state); return NULL; } return state; } /* async version of receive control reply */ int ctdb_control_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status, char **errormsg) { TALLOC_CTX *tmp_ctx; if (status != NULL) { *status = -1; } if (errormsg != NULL) { *errormsg = NULL; } if (state == NULL) { return -1; } /* prevent double free of state */ tmp_ctx = talloc_new(ctdb); talloc_steal(tmp_ctx, state); /* loop one event at a time until we either timeout or the control completes. */ while (state->state == CTDB_CONTROL_WAIT) { event_loop_once(ctdb->ev); } if (state->state != CTDB_CONTROL_DONE) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control_recv failed\n")); if (state->async.fn) { state->async.fn(state); } talloc_free(tmp_ctx); return -1; } if (state->errormsg) { DEBUG(DEBUG_ERR,("ctdb_control error: '%s'\n", state->errormsg)); if (errormsg) { (*errormsg) = talloc_move(mem_ctx, &state->errormsg); } if (state->async.fn) { state->async.fn(state); } talloc_free(tmp_ctx); return -1; } if (outdata) { *outdata = state->outdata; outdata->dptr = talloc_memdup(mem_ctx, outdata->dptr, outdata->dsize); } if (status) { *status = state->status; } if (state->async.fn) { state->async.fn(state); } talloc_free(tmp_ctx); return 0; } /* send a ctdb control message timeout specifies how long we should wait for a reply. if timeout is NULL we wait indefinitely */ int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, uint32_t opcode, uint32_t flags, TDB_DATA data, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status, struct timeval *timeout, char **errormsg) { struct ctdb_client_control_state *state; state = ctdb_control_send(ctdb, destnode, srvid, opcode, flags, data, mem_ctx, timeout, errormsg); /* FIXME: Error conditions in ctdb_control_send return NULL without * setting errormsg. So, there is no way to distinguish between sucess * and failure when CTDB_CTRL_FLAG_NOREPLY is set */ if (flags & CTDB_CTRL_FLAG_NOREPLY) { if (status != NULL) { *status = 0; } return 0; } return ctdb_control_recv(ctdb, state, mem_ctx, outdata, status, errormsg); } /* a process exists call. Returns 0 if process exists, -1 otherwise */ int ctdb_ctrl_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid) { int ret; TDB_DATA data; int32_t status; data.dptr = (uint8_t*)&pid; data.dsize = sizeof(pid); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_PROCESS_EXISTS, 0, data, NULL, NULL, &status, NULL, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for process_exists failed\n")); return -1; } return status; } /* get remote statistics */ int ctdb_ctrl_statistics(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_statistics *status) { int ret; TDB_DATA data; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_STATISTICS, 0, tdb_null, ctdb, &data, &res, NULL, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for statistics failed\n")); return -1; } if (data.dsize != sizeof(struct ctdb_statistics)) { DEBUG(DEBUG_ERR,(__location__ " Wrong statistics size %u - expected %u\n", (unsigned)data.dsize, (unsigned)sizeof(struct ctdb_statistics))); return -1; } *status = *(struct ctdb_statistics *)data.dptr; talloc_free(data.dptr); return 0; } /* * get db statistics */ int ctdb_ctrl_dbstatistics(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, struct ctdb_db_statistics **dbstat) { int ret; TDB_DATA indata, outdata; int32_t res; struct ctdb_db_statistics *wire, *s; char *ptr; int i; indata.dptr = (uint8_t *)&dbid; indata.dsize = sizeof(dbid); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DB_STATISTICS, 0, indata, ctdb, &outdata, &res, NULL, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for dbstatistics failed\n")); return -1; } if (outdata.dsize < offsetof(struct ctdb_db_statistics, hot_keys_wire)) { DEBUG(DEBUG_ERR,(__location__ " Wrong dbstatistics size %zi - expected >= %lu\n", outdata.dsize, (long unsigned int)sizeof(struct ctdb_statistics))); return -1; } s = talloc_zero(mem_ctx, struct ctdb_db_statistics); if (s == NULL) { talloc_free(outdata.dptr); CTDB_NO_MEMORY(ctdb, s); } wire = (struct ctdb_db_statistics *)outdata.dptr; *s = *wire; ptr = &wire->hot_keys_wire[0]; for (i=0; inum_hot_keys; i++) { s->hot_keys[i].key.dptr = talloc_size(mem_ctx, s->hot_keys[i].key.dsize); if (s->hot_keys[i].key.dptr == NULL) { talloc_free(outdata.dptr); CTDB_NO_MEMORY(ctdb, s->hot_keys[i].key.dptr); } memcpy(s->hot_keys[i].key.dptr, ptr, s->hot_keys[i].key.dsize); ptr += wire->hot_keys[i].key.dsize; } talloc_free(outdata.dptr); *dbstat = s; return 0; } /* shutdown a remote ctdb node */ int ctdb_ctrl_shutdown(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { struct ctdb_client_control_state *state; state = ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_SHUTDOWN, 0, tdb_null, NULL, &timeout, NULL); if (state == NULL) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for shutdown failed\n")); return -1; } return 0; } /* get vnn map from a remote node */ int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_vnn_map **vnnmap) { int ret; TDB_DATA outdata; int32_t res; struct ctdb_vnn_map_wire *map; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GETVNNMAP, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getvnnmap failed\n")); return -1; } map = (struct ctdb_vnn_map_wire *)outdata.dptr; if (outdata.dsize < offsetof(struct ctdb_vnn_map_wire, map) || outdata.dsize != map->size*sizeof(uint32_t) + offsetof(struct ctdb_vnn_map_wire, map)) { DEBUG(DEBUG_ERR,("Bad vnn map size received in ctdb_ctrl_getvnnmap\n")); return -1; } (*vnnmap) = talloc(mem_ctx, struct ctdb_vnn_map); CTDB_NO_MEMORY(ctdb, *vnnmap); (*vnnmap)->generation = map->generation; (*vnnmap)->size = map->size; (*vnnmap)->map = talloc_array(*vnnmap, uint32_t, map->size); CTDB_NO_MEMORY(ctdb, (*vnnmap)->map); memcpy((*vnnmap)->map, map->map, sizeof(uint32_t)*map->size); talloc_free(outdata.dptr); return 0; } /* get the recovery mode of a remote node */ struct ctdb_client_control_state * ctdb_ctrl_getrecmode_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode) { return ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_GET_RECMODE, 0, tdb_null, mem_ctx, &timeout, NULL); } int ctdb_ctrl_getrecmode_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmode) { int ret; int32_t res; ret = ctdb_control_recv(ctdb, state, mem_ctx, NULL, &res, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_getrecmode_recv failed\n")); return -1; } if (recmode) { *recmode = (uint32_t)res; } return 0; } int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmode) { struct ctdb_client_control_state *state; state = ctdb_ctrl_getrecmode_send(ctdb, mem_ctx, timeout, destnode); return ctdb_ctrl_getrecmode_recv(ctdb, mem_ctx, state, recmode); } /* set the recovery mode of a remote node */ int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmode) { int ret; TDB_DATA data; int32_t res; data.dsize = sizeof(uint32_t); data.dptr = (unsigned char *)&recmode; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_RECMODE, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setrecmode failed\n")); return -1; } return 0; } /* get the recovery master of a remote node */ struct ctdb_client_control_state * ctdb_ctrl_getrecmaster_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode) { return ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_GET_RECMASTER, 0, tdb_null, mem_ctx, &timeout, NULL); } int ctdb_ctrl_getrecmaster_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmaster) { int ret; int32_t res; ret = ctdb_control_recv(ctdb, state, mem_ctx, NULL, &res, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_getrecmaster_recv failed\n")); return -1; } if (recmaster) { *recmaster = (uint32_t)res; } return 0; } int ctdb_ctrl_getrecmaster(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmaster) { struct ctdb_client_control_state *state; state = ctdb_ctrl_getrecmaster_send(ctdb, mem_ctx, timeout, destnode); return ctdb_ctrl_getrecmaster_recv(ctdb, mem_ctx, state, recmaster); } /* set the recovery master of a remote node */ int ctdb_ctrl_setrecmaster(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmaster) { int ret; TDB_DATA data; int32_t res; ZERO_STRUCT(data); data.dsize = sizeof(uint32_t); data.dptr = (unsigned char *)&recmaster; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_RECMASTER, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setrecmaster failed\n")); return -1; } return 0; } /* get a list of databases off a remote node */ int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_dbid_map **dbmap) { int ret; TDB_DATA outdata; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DBMAP, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getdbmap failed ret:%d res:%d\n", ret, res)); return -1; } *dbmap = (struct ctdb_dbid_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize); talloc_free(outdata.dptr); return 0; } /* get a list of nodes (vnn and flags ) from a remote node */ int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap) { int ret; TDB_DATA outdata; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_NODEMAP, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret == 0 && res == -1 && outdata.dsize == 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodes failed, falling back to ipv4-only control\n")); return ctdb_ctrl_getnodemapv4(ctdb, timeout, destnode, mem_ctx, nodemap); } if (ret != 0 || res != 0 || outdata.dsize == 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodes failed ret:%d res:%d\n", ret, res)); return -1; } *nodemap = (struct ctdb_node_map *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize); talloc_free(outdata.dptr); return 0; } /* old style ipv4-only get a list of nodes (vnn and flags ) from a remote node */ int ctdb_ctrl_getnodemapv4(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap) { int ret, i, len; TDB_DATA outdata; struct ctdb_node_mapv4 *nodemapv4; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_NODEMAPv4, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0 || outdata.dsize == 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getnodesv4 failed ret:%d res:%d\n", ret, res)); return -1; } nodemapv4 = (struct ctdb_node_mapv4 *)outdata.dptr; len = offsetof(struct ctdb_node_map, nodes) + nodemapv4->num*sizeof(struct ctdb_node_and_flags); (*nodemap) = talloc_zero_size(mem_ctx, len); CTDB_NO_MEMORY(ctdb, (*nodemap)); (*nodemap)->num = nodemapv4->num; for (i=0; inum; i++) { (*nodemap)->nodes[i].pnn = nodemapv4->nodes[i].pnn; (*nodemap)->nodes[i].flags = nodemapv4->nodes[i].flags; (*nodemap)->nodes[i].addr.ip = nodemapv4->nodes[i].sin; (*nodemap)->nodes[i].addr.sa.sa_family = AF_INET; } talloc_free(outdata.dptr); return 0; } /* drop the transport, reload the nodes file and restart the transport */ int ctdb_ctrl_reload_nodes_file(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { int ret; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELOAD_NODES_FILE, 0, tdb_null, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for reloadnodesfile failed\n")); return -1; } return 0; } /* set vnn map on a node */ int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *vnnmap) { int ret; TDB_DATA data; int32_t res; struct ctdb_vnn_map_wire *map; size_t len; len = offsetof(struct ctdb_vnn_map_wire, map) + sizeof(uint32_t)*vnnmap->size; map = talloc_size(mem_ctx, len); CTDB_NO_MEMORY(ctdb, map); map->generation = vnnmap->generation; map->size = vnnmap->size; memcpy(map->map, vnnmap->map, sizeof(uint32_t)*map->size); data.dsize = len; data.dptr = (uint8_t *)map; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SETVNNMAP, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setvnnmap failed\n")); return -1; } talloc_free(map); return 0; } /* async send for pull database */ struct ctdb_client_control_state *ctdb_ctrl_pulldb_send( struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout) { TDB_DATA indata; struct ctdb_control_pulldb *pull; struct ctdb_client_control_state *state; pull = talloc(mem_ctx, struct ctdb_control_pulldb); CTDB_NO_MEMORY_NULL(ctdb, pull); pull->db_id = dbid; pull->lmaster = lmaster; indata.dsize = sizeof(struct ctdb_control_pulldb); indata.dptr = (unsigned char *)pull; state = ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_PULL_DB, 0, indata, mem_ctx, &timeout, NULL); talloc_free(pull); return state; } /* async recv for pull database */ int ctdb_ctrl_pulldb_recv( struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, TDB_DATA *outdata) { int ret; int32_t res; ret = ctdb_control_recv(ctdb, state, mem_ctx, outdata, &res, NULL); if ( (ret != 0) || (res != 0) ){ DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_pulldb_recv failed\n")); return -1; } return 0; } /* pull all keys and records for a specific database on a node */ int ctdb_ctrl_pulldb(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout, TDB_DATA *outdata) { struct ctdb_client_control_state *state; state = ctdb_ctrl_pulldb_send(ctdb, destnode, dbid, lmaster, mem_ctx, timeout); return ctdb_ctrl_pulldb_recv(ctdb, mem_ctx, state, outdata); } /* change dmaster for all keys in the database to the new value */ int ctdb_ctrl_setdmaster(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, uint32_t dbid, uint32_t dmaster) { int ret; TDB_DATA indata; int32_t res; indata.dsize = 2*sizeof(uint32_t); indata.dptr = (unsigned char *)talloc_array(mem_ctx, uint32_t, 2); ((uint32_t *)(&indata.dptr[0]))[0] = dbid; ((uint32_t *)(&indata.dptr[0]))[1] = dmaster; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_DMASTER, 0, indata, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setdmaster failed\n")); return -1; } return 0; } /* ping a node, return number of clients connected */ int ctdb_ctrl_ping(struct ctdb_context *ctdb, uint32_t destnode) { int ret; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_PING, 0, tdb_null, NULL, NULL, &res, NULL, NULL); if (ret != 0) { return -1; } return res; } int ctdb_ctrl_get_runstate(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *runstate) { TDB_DATA outdata; int32_t res; int ret; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_RUNSTATE, 0, tdb_null, ctdb, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("ctdb_control for get_runstate failed\n")); return ret != 0 ? ret : res; } if (outdata.dsize != sizeof(uint32_t)) { DEBUG(DEBUG_ERR,("Invalid return data in get_runstate\n")); talloc_free(outdata.dptr); return -1; } if (runstate != NULL) { *runstate = *(uint32_t *)outdata.dptr; } talloc_free(outdata.dptr); return 0; } /* find the real path to a ltdb */ int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **path) { int ret; int32_t res; TDB_DATA data; data.dptr = (uint8_t *)&dbid; data.dsize = sizeof(dbid); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GETDBPATH, 0, data, mem_ctx, &data, &res, &timeout, NULL); if (ret != 0 || res != 0) { return -1; } (*path) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize); if ((*path) == NULL) { return -1; } talloc_free(data.dptr); return 0; } /* find the name of a db */ int ctdb_ctrl_getdbname(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **name) { int ret; int32_t res; TDB_DATA data; data.dptr = (uint8_t *)&dbid; data.dsize = sizeof(dbid); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DBNAME, 0, data, mem_ctx, &data, &res, &timeout, NULL); if (ret != 0 || res != 0) { return -1; } (*name) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize); if ((*name) == NULL) { return -1; } talloc_free(data.dptr); return 0; } /* get the health status of a db */ int ctdb_ctrl_getdbhealth(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **reason) { int ret; int32_t res; TDB_DATA data; data.dptr = (uint8_t *)&dbid; data.dsize = sizeof(dbid); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_DB_GET_HEALTH, 0, data, mem_ctx, &data, &res, &timeout, NULL); if (ret != 0 || res != 0) { return -1; } if (data.dsize == 0) { (*reason) = NULL; return 0; } (*reason) = talloc_strndup(mem_ctx, (const char *)data.dptr, data.dsize); if ((*reason) == NULL) { return -1; } talloc_free(data.dptr); return 0; } /* * get db sequence number */ int ctdb_ctrl_getdbseqnum(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, uint64_t *seqnum) { int ret; int32_t res; TDB_DATA data, outdata; data.dptr = (uint8_t *)&dbid; data.dsize = sizeof(uint64_t); /* This is just wrong */ ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DB_SEQNUM, 0, data, ctdb, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("ctdb_control for getdbesqnum failed\n")); return -1; } if (outdata.dsize != sizeof(uint64_t)) { DEBUG(DEBUG_ERR,("Invalid return data in get_dbseqnum\n")); talloc_free(outdata.dptr); return -1; } if (seqnum != NULL) { *seqnum = *(uint64_t *)outdata.dptr; } talloc_free(outdata.dptr); return 0; } /* create a database */ int ctdb_ctrl_createdb(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const char *name, bool persistent) { int ret; int32_t res; TDB_DATA data; uint64_t tdb_flags = 0; data.dptr = discard_const(name); data.dsize = strlen(name)+1; /* Make sure that volatile databases use jenkins hash */ if (!persistent) { tdb_flags = TDB_INCOMPATIBLE_HASH; } ret = ctdb_control(ctdb, destnode, tdb_flags, persistent?CTDB_CONTROL_DB_ATTACH_PERSISTENT:CTDB_CONTROL_DB_ATTACH, 0, data, mem_ctx, &data, &res, &timeout, NULL); if (ret != 0 || res != 0) { return -1; } return 0; } /* get debug level on a node */ int ctdb_ctrl_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t *level) { int ret; int32_t res; TDB_DATA data; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DEBUG, 0, tdb_null, ctdb, &data, &res, NULL, NULL); if (ret != 0 || res != 0) { return -1; } if (data.dsize != sizeof(int32_t)) { DEBUG(DEBUG_ERR,("Bad control reply size in ctdb_get_debuglevel (got %u)\n", (unsigned)data.dsize)); return -1; } *level = *(int32_t *)data.dptr; talloc_free(data.dptr); return 0; } /* set debug level on a node */ int ctdb_ctrl_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t level) { int ret; int32_t res; TDB_DATA data; data.dptr = (uint8_t *)&level; data.dsize = sizeof(level); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_DEBUG, 0, data, NULL, NULL, &res, NULL, NULL); if (ret != 0 || res != 0) { return -1; } return 0; } /* get a list of connected nodes */ uint32_t *ctdb_get_connected_nodes(struct ctdb_context *ctdb, struct timeval timeout, TALLOC_CTX *mem_ctx, uint32_t *num_nodes) { struct ctdb_node_map *map=NULL; int ret, i; uint32_t *nodes; *num_nodes = 0; ret = ctdb_ctrl_getnodemap(ctdb, timeout, CTDB_CURRENT_NODE, mem_ctx, &map); if (ret != 0) { return NULL; } nodes = talloc_array(mem_ctx, uint32_t, map->num); if (nodes == NULL) { return NULL; } for (i=0;inum;i++) { if (!(map->nodes[i].flags & NODE_FLAGS_DISCONNECTED)) { nodes[*num_nodes] = map->nodes[i].pnn; (*num_nodes)++; } } return nodes; } /* reset remote status */ int ctdb_statistics_reset(struct ctdb_context *ctdb, uint32_t destnode) { int ret; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_STATISTICS_RESET, 0, tdb_null, NULL, NULL, &res, NULL, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for reset statistics failed\n")); return -1; } return 0; } /* attach to a specific database - client call */ struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb, struct timeval timeout, const char *name, bool persistent, uint32_t tdb_flags) { struct ctdb_db_context *ctdb_db; TDB_DATA data; int ret; int32_t res; ctdb_db = ctdb_db_handle(ctdb, name); if (ctdb_db) { return ctdb_db; } ctdb_db = talloc_zero(ctdb, struct ctdb_db_context); CTDB_NO_MEMORY_NULL(ctdb, ctdb_db); ctdb_db->ctdb = ctdb; ctdb_db->db_name = talloc_strdup(ctdb_db, name); CTDB_NO_MEMORY_NULL(ctdb, ctdb_db->db_name); data.dptr = discard_const(name); data.dsize = strlen(name)+1; /* CTDB has switched to using jenkins hash for volatile databases. * Even if tdb_flags do not explicitly mention TDB_INCOMPATIBLE_HASH, * always set it. */ if (!persistent) { tdb_flags |= TDB_INCOMPATIBLE_HASH; } /* tell ctdb daemon to attach */ ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, tdb_flags, persistent?CTDB_CONTROL_DB_ATTACH_PERSISTENT:CTDB_CONTROL_DB_ATTACH, 0, data, ctdb_db, &data, &res, NULL, NULL); if (ret != 0 || res != 0 || data.dsize != sizeof(uint32_t)) { DEBUG(DEBUG_ERR,("Failed to attach to database '%s'\n", name)); talloc_free(ctdb_db); return NULL; } ctdb_db->db_id = *(uint32_t *)data.dptr; talloc_free(data.dptr); ret = ctdb_ctrl_getdbpath(ctdb, timeout, CTDB_CURRENT_NODE, ctdb_db->db_id, ctdb_db, &ctdb_db->db_path); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to get dbpath for database '%s'\n", name)); talloc_free(ctdb_db); return NULL; } tdb_flags = persistent?TDB_DEFAULT:TDB_NOSYNC; if (ctdb->valgrinding) { tdb_flags |= TDB_NOMMAP; } tdb_flags |= TDB_DISALLOW_NESTING; ctdb_db->ltdb = tdb_wrap_open(ctdb, ctdb_db->db_path, 0, tdb_flags, O_RDWR, 0); if (ctdb_db->ltdb == NULL) { ctdb_set_error(ctdb, "Failed to open tdb '%s'\n", ctdb_db->db_path); talloc_free(ctdb_db); return NULL; } ctdb_db->persistent = persistent; DLIST_ADD(ctdb->db_list, ctdb_db); /* add well known functions */ ctdb_set_call(ctdb_db, ctdb_null_func, CTDB_NULL_FUNC); ctdb_set_call(ctdb_db, ctdb_fetch_func, CTDB_FETCH_FUNC); ctdb_set_call(ctdb_db, ctdb_fetch_with_header_func, CTDB_FETCH_WITH_HEADER_FUNC); return ctdb_db; } /* setup a call for a database */ int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id) { struct ctdb_registered_call *call; #if 0 TDB_DATA data; int32_t status; struct ctdb_control_set_call c; int ret; /* this is no longer valid with the separate daemon architecture */ c.db_id = ctdb_db->db_id; c.fn = fn; c.id = id; data.dptr = (uint8_t *)&c; data.dsize = sizeof(c); ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_SET_CALL, 0, data, NULL, NULL, &status, NULL, NULL); if (ret != 0 || status != 0) { DEBUG(DEBUG_ERR,("ctdb_set_call failed for call %u\n", id)); return -1; } #endif /* also register locally */ call = talloc(ctdb_db, struct ctdb_registered_call); call->fn = fn; call->id = id; DLIST_ADD(ctdb_db->calls, call); return 0; } struct traverse_state { bool done; uint32_t count; ctdb_traverse_func fn; void *private_data; bool listemptyrecords; }; /* called on each key during a ctdb_traverse */ static void traverse_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *p) { struct traverse_state *state = (struct traverse_state *)p; struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr; TDB_DATA key; if (data.dsize < sizeof(uint32_t) || d->length != data.dsize) { DEBUG(DEBUG_ERR,("Bad data size %u in traverse_handler\n", (unsigned)data.dsize)); state->done = true; return; } key.dsize = d->keylen; key.dptr = &d->data[0]; data.dsize = d->datalen; data.dptr = &d->data[d->keylen]; if (key.dsize == 0 && data.dsize == 0) { /* end of traverse */ state->done = true; return; } if (!state->listemptyrecords && data.dsize == sizeof(struct ctdb_ltdb_header)) { /* empty records are deleted records in ctdb */ return; } if (state->fn(ctdb, key, data, state->private_data) != 0) { state->done = true; } state->count++; } /** * start a cluster wide traverse, calling the supplied fn on each record * return the number of records traversed, or -1 on error * * Extendet variant with a flag to signal whether empty records should * be listed. */ static int ctdb_traverse_ext(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, bool withemptyrecords, void *private_data) { TDB_DATA data; struct ctdb_traverse_start_ext t; int32_t status; int ret; uint64_t srvid = (getpid() | 0xFLL<<60); struct traverse_state state; state.done = false; state.count = 0; state.private_data = private_data; state.fn = fn; state.listemptyrecords = withemptyrecords; ret = ctdb_client_set_message_handler(ctdb_db->ctdb, srvid, traverse_handler, &state); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to setup traverse handler\n")); return -1; } t.db_id = ctdb_db->db_id; t.srvid = srvid; t.reqid = 0; t.withemptyrecords = withemptyrecords; data.dptr = (uint8_t *)&t; data.dsize = sizeof(t); ret = ctdb_control(ctdb_db->ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_TRAVERSE_START_EXT, 0, data, NULL, NULL, &status, NULL, NULL); if (ret != 0 || status != 0) { DEBUG(DEBUG_ERR,("ctdb_traverse_all failed\n")); ctdb_client_remove_message_handler(ctdb_db->ctdb, srvid, &state); return -1; } while (!state.done) { event_loop_once(ctdb_db->ctdb->ev); } ret = ctdb_client_remove_message_handler(ctdb_db->ctdb, srvid, &state); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to remove ctdb_traverse handler\n")); return -1; } return state.count; } /** * start a cluster wide traverse, calling the supplied fn on each record * return the number of records traversed, or -1 on error * * Standard version which does not list the empty records: * These are considered deleted. */ int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *private_data) { return ctdb_traverse_ext(ctdb_db, fn, false, private_data); } #define ISASCII(x) (isprint(x) && !strchr("\"\\", (x))) /* called on each key during a catdb */ int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p) { int i; struct ctdb_dump_db_context *c = (struct ctdb_dump_db_context *)p; FILE *f = c->f; struct ctdb_ltdb_header *h = (struct ctdb_ltdb_header *)data.dptr; fprintf(f, "key(%u) = \"", (unsigned)key.dsize); for (i=0;idmaster); fprintf(f, "rsn: %llu\n", (unsigned long long)h->rsn); if (c->printlmaster && ctdb->vnn_map != NULL) { fprintf(f, "lmaster: %u\n", ctdb_lmaster(ctdb, &key)); } if (c->printhash) { fprintf(f, "hash: 0x%08x\n", ctdb_hash(&key)); } if (c->printrecordflags) { fprintf(f, "flags: 0x%08x", h->flags); if (h->flags & CTDB_REC_FLAG_MIGRATED_WITH_DATA) printf(" MIGRATED_WITH_DATA"); if (h->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) printf(" VACUUM_MIGRATED"); if (h->flags & CTDB_REC_FLAG_AUTOMATIC) printf(" AUTOMATIC"); if (h->flags & CTDB_REC_RO_HAVE_DELEGATIONS) printf(" RO_HAVE_DELEGATIONS"); if (h->flags & CTDB_REC_RO_HAVE_READONLY) printf(" RO_HAVE_READONLY"); if (h->flags & CTDB_REC_RO_REVOKING_READONLY) printf(" RO_REVOKING_READONLY"); if (h->flags & CTDB_REC_RO_REVOKE_COMPLETE) printf(" RO_REVOKE_COMPLETE"); fprintf(f, "\n"); } if (c->printdatasize) { fprintf(f, "data size: %u\n", (unsigned)data.dsize); } else { fprintf(f, "data(%u) = \"", (unsigned)(data.dsize - sizeof(*h))); for (i=sizeof(*h);iprintemptyrecords, ctx); } /* get the pid of a ctdb daemon */ int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *pid) { int ret; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_PID, 0, tdb_null, NULL, NULL, &res, &timeout, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpid failed\n")); return -1; } *pid = res; return 0; } /* async freeze send control */ struct ctdb_client_control_state * ctdb_ctrl_freeze_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t priority) { return ctdb_control_send(ctdb, destnode, priority, CTDB_CONTROL_FREEZE, 0, tdb_null, mem_ctx, &timeout, NULL); } /* async freeze recv control */ int ctdb_ctrl_freeze_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state) { int ret; int32_t res; ret = ctdb_control_recv(ctdb, state, mem_ctx, NULL, &res, NULL); if ( (ret != 0) || (res != 0) ){ DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_freeze_recv failed\n")); return -1; } return 0; } /* freeze databases of a certain priority */ int ctdb_ctrl_freeze_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t priority) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_client_control_state *state; int ret; state = ctdb_ctrl_freeze_send(ctdb, tmp_ctx, timeout, destnode, priority); ret = ctdb_ctrl_freeze_recv(ctdb, tmp_ctx, state); talloc_free(tmp_ctx); return ret; } /* Freeze all databases */ int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { int i; for (i=1; i<=NUM_DB_PRIORITIES; i++) { if (ctdb_ctrl_freeze_priority(ctdb, timeout, destnode, i) != 0) { return -1; } } return 0; } /* thaw databases of a certain priority */ int ctdb_ctrl_thaw_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t priority) { int ret; int32_t res; ret = ctdb_control(ctdb, destnode, priority, CTDB_CONTROL_THAW, 0, tdb_null, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control thaw failed\n")); return -1; } return 0; } /* thaw all databases */ int ctdb_ctrl_thaw(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { return ctdb_ctrl_thaw_priority(ctdb, timeout, destnode, 0); } /* get pnn of a node, or -1 */ int ctdb_ctrl_getpnn(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { int ret; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_PNN, 0, tdb_null, NULL, NULL, &res, &timeout, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpnn failed\n")); return -1; } return res; } /* get the monitoring mode of a remote node */ int ctdb_ctrl_getmonmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *monmode) { int ret; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_MONMODE, 0, tdb_null, NULL, NULL, &res, &timeout, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getmonmode failed\n")); return -1; } *monmode = res; return 0; } /* set the monitoring mode of a remote node to active */ int ctdb_ctrl_enable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { int ret; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_ENABLE_MONITOR, 0, tdb_null, NULL, NULL,NULL, &timeout, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for enable_monitor failed\n")); return -1; } return 0; } /* set the monitoring mode of a remote node to disable */ int ctdb_ctrl_disable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { int ret; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_DISABLE_MONITOR, 0, tdb_null, NULL, NULL, NULL, &timeout, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for disable_monitor failed\n")); return -1; } return 0; } /* sent to a node to make it take over an ip address */ int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_public_ip *ip) { TDB_DATA data; struct ctdb_public_ipv4 ipv4; int ret; int32_t res; if (ip->addr.sa.sa_family == AF_INET) { ipv4.pnn = ip->pnn; ipv4.sin = ip->addr.ip; data.dsize = sizeof(ipv4); data.dptr = (uint8_t *)&ipv4; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_TAKEOVER_IPv4, 0, data, NULL, NULL, &res, &timeout, NULL); } else { data.dsize = sizeof(*ip); data.dptr = (uint8_t *)ip; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_TAKEOVER_IP, 0, data, NULL, NULL, &res, &timeout, NULL); } if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for takeover_ip failed\n")); return -1; } return 0; } /* sent to a node to make it release an ip address */ int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_public_ip *ip) { TDB_DATA data; struct ctdb_public_ipv4 ipv4; int ret; int32_t res; if (ip->addr.sa.sa_family == AF_INET) { ipv4.pnn = ip->pnn; ipv4.sin = ip->addr.ip; data.dsize = sizeof(ipv4); data.dptr = (uint8_t *)&ipv4; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELEASE_IPv4, 0, data, NULL, NULL, &res, &timeout, NULL); } else { data.dsize = sizeof(*ip); data.dptr = (uint8_t *)ip; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELEASE_IP, 0, data, NULL, NULL, &res, &timeout, NULL); } if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for release_ip failed\n")); return -1; } return 0; } /* get a tunable */ int ctdb_ctrl_get_tunable(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *name, uint32_t *value) { struct ctdb_control_get_tunable *t; TDB_DATA data, outdata; int32_t res; int ret; data.dsize = offsetof(struct ctdb_control_get_tunable, name) + strlen(name) + 1; data.dptr = talloc_size(ctdb, data.dsize); CTDB_NO_MEMORY(ctdb, data.dptr); t = (struct ctdb_control_get_tunable *)data.dptr; t->length = strlen(name)+1; memcpy(t->name, name, t->length); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_TUNABLE, 0, data, ctdb, &outdata, &res, &timeout, NULL); talloc_free(data.dptr); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get_tunable failed\n")); return ret != 0 ? ret : res; } if (outdata.dsize != sizeof(uint32_t)) { DEBUG(DEBUG_ERR,("Invalid return data in get_tunable\n")); talloc_free(outdata.dptr); return -1; } *value = *(uint32_t *)outdata.dptr; talloc_free(outdata.dptr); return 0; } /* set a tunable */ int ctdb_ctrl_set_tunable(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *name, uint32_t value) { struct ctdb_control_set_tunable *t; TDB_DATA data; int32_t res; int ret; data.dsize = offsetof(struct ctdb_control_set_tunable, name) + strlen(name) + 1; data.dptr = talloc_size(ctdb, data.dsize); CTDB_NO_MEMORY(ctdb, data.dptr); t = (struct ctdb_control_set_tunable *)data.dptr; t->length = strlen(name)+1; memcpy(t->name, name, t->length); t->value = value; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_TUNABLE, 0, data, NULL, NULL, &res, &timeout, NULL); talloc_free(data.dptr); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set_tunable failed\n")); return -1; } return 0; } /* list tunables */ int ctdb_ctrl_list_tunables(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const char ***list, uint32_t *count) { TDB_DATA outdata; int32_t res; int ret; struct ctdb_control_list_tunable *t; char *p, *s, *ptr; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_LIST_TUNABLES, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for list_tunables failed\n")); return -1; } t = (struct ctdb_control_list_tunable *)outdata.dptr; if (outdata.dsize < offsetof(struct ctdb_control_list_tunable, data) || t->length > outdata.dsize-offsetof(struct ctdb_control_list_tunable, data)) { DEBUG(DEBUG_ERR,("Invalid data in list_tunables reply\n")); talloc_free(outdata.dptr); return -1; } p = talloc_strndup(mem_ctx, (char *)t->data, t->length); CTDB_NO_MEMORY(ctdb, p); talloc_free(outdata.dptr); (*list) = NULL; (*count) = 0; for (s=strtok_r(p, ":", &ptr); s; s=strtok_r(NULL, ":", &ptr)) { (*list) = talloc_realloc(mem_ctx, *list, const char *, 1+(*count)); CTDB_NO_MEMORY(ctdb, *list); (*list)[*count] = talloc_strdup(*list, s); CTDB_NO_MEMORY(ctdb, (*list)[*count]); (*count)++; } talloc_free(p); return 0; } int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, uint32_t flags, struct ctdb_all_public_ips **ips) { int ret; TDB_DATA outdata; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_PUBLIC_IPS, flags, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret == 0 && res == -1) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control to get public ips failed, falling back to ipv4-only version\n")); return ctdb_ctrl_get_public_ipsv4(ctdb, timeout, destnode, mem_ctx, ips); } if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpublicips failed ret:%d res:%d\n", ret, res)); return -1; } *ips = (struct ctdb_all_public_ips *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize); talloc_free(outdata.dptr); return 0; } int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips) { return ctdb_ctrl_get_public_ips_flags(ctdb, timeout, destnode, mem_ctx, 0, ips); } int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips) { int ret, i, len; TDB_DATA outdata; int32_t res; struct ctdb_all_public_ipsv4 *ipsv4; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_PUBLIC_IPSv4, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getpublicips failed\n")); return -1; } ipsv4 = (struct ctdb_all_public_ipsv4 *)outdata.dptr; len = offsetof(struct ctdb_all_public_ips, ips) + ipsv4->num*sizeof(struct ctdb_public_ip); *ips = talloc_zero_size(mem_ctx, len); CTDB_NO_MEMORY(ctdb, *ips); (*ips)->num = ipsv4->num; for (i=0; inum; i++) { (*ips)->ips[i].pnn = ipsv4->ips[i].pnn; (*ips)->ips[i].addr.ip = ipsv4->ips[i].sin; } talloc_free(outdata.dptr); return 0; } int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const ctdb_sock_addr *addr, struct ctdb_control_public_ip_info **_info) { int ret; TDB_DATA indata; TDB_DATA outdata; int32_t res; struct ctdb_control_public_ip_info *info; uint32_t len; uint32_t i; indata.dptr = discard_const_p(uint8_t, addr); indata.dsize = sizeof(*addr); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_PUBLIC_IP_INFO, 0, indata, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info " "failed ret:%d res:%d\n", ret, res)); return -1; } len = offsetof(struct ctdb_control_public_ip_info, ifaces); if (len > outdata.dsize) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info " "returned invalid data with size %u > %u\n", (unsigned int)outdata.dsize, (unsigned int)len)); dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize); return -1; } info = (struct ctdb_control_public_ip_info *)outdata.dptr; len += info->num*sizeof(struct ctdb_control_iface_info); if (len > outdata.dsize) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info " "returned invalid data with size %u > %u\n", (unsigned int)outdata.dsize, (unsigned int)len)); dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize); return -1; } /* make sure we null terminate the returned strings */ for (i=0; i < info->num; i++) { info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0'; } *_info = (struct ctdb_control_public_ip_info *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize); talloc_free(outdata.dptr); if (*_info == NULL) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info " "talloc_memdup size %u failed\n", (unsigned int)outdata.dsize)); return -1; } return 0; } int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_control_get_ifaces **_ifaces) { int ret; TDB_DATA outdata; int32_t res; struct ctdb_control_get_ifaces *ifaces; uint32_t len; uint32_t i; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_IFACES, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces " "failed ret:%d res:%d\n", ret, res)); return -1; } len = offsetof(struct ctdb_control_get_ifaces, ifaces); if (len > outdata.dsize) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces " "returned invalid data with size %u > %u\n", (unsigned int)outdata.dsize, (unsigned int)len)); dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize); return -1; } ifaces = (struct ctdb_control_get_ifaces *)outdata.dptr; len += ifaces->num*sizeof(struct ctdb_control_iface_info); if (len > outdata.dsize) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces " "returned invalid data with size %u > %u\n", (unsigned int)outdata.dsize, (unsigned int)len)); dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize); return -1; } /* make sure we null terminate the returned strings */ for (i=0; i < ifaces->num; i++) { ifaces->ifaces[i].name[CTDB_IFACE_SIZE] = '\0'; } *_ifaces = (struct ctdb_control_get_ifaces *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize); talloc_free(outdata.dptr); if (*_ifaces == NULL) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces " "talloc_memdup size %u failed\n", (unsigned int)outdata.dsize)); return -1; } return 0; } int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const struct ctdb_control_iface_info *info) { int ret; TDB_DATA indata; int32_t res; indata.dptr = discard_const_p(uint8_t, info); indata.dsize = sizeof(*info); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_IFACE_LINK_STATE, 0, indata, mem_ctx, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set iface link " "failed ret:%d res:%d\n", ret, res)); return -1; } return 0; } /* set/clear the permanent disabled bit on a remote node */ int ctdb_ctrl_modflags(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t set, uint32_t clear) { int ret; TDB_DATA data; struct ctdb_node_map *nodemap=NULL; struct ctdb_node_flag_change c; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); uint32_t recmaster; uint32_t *nodes; /* find the recovery master */ ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, timeout, CTDB_CURRENT_NODE, &recmaster); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to get recmaster from local node\n")); talloc_free(tmp_ctx); return ret; } /* read the node flags from the recmaster */ ret = ctdb_ctrl_getnodemap(ctdb, timeout, recmaster, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to get nodemap from node %u\n", destnode)); talloc_free(tmp_ctx); return -1; } if (destnode >= nodemap->num) { DEBUG(DEBUG_ERR,(__location__ " Nodemap from recmaster does not contain node %d\n", destnode)); talloc_free(tmp_ctx); return -1; } c.pnn = destnode; c.old_flags = nodemap->nodes[destnode].flags; c.new_flags = c.old_flags; c.new_flags |= set; c.new_flags &= ~clear; data.dsize = sizeof(c); data.dptr = (unsigned char *)&c; /* send the flags update to all connected nodes */ nodes = list_of_connected_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_MODIFY_FLAGS, nodes, 0, timeout, false, data, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, (__location__ " Unable to update nodeflags on remote nodes\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } /* get all tunables */ int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_tunable *tunables) { TDB_DATA outdata; int ret; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_ALL_TUNABLES, 0, tdb_null, ctdb, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get all tunables failed\n")); return -1; } if (outdata.dsize != sizeof(*tunables)) { DEBUG(DEBUG_ERR,(__location__ " bad data size %u in ctdb_ctrl_get_all_tunables should be %u\n", (unsigned)outdata.dsize, (unsigned)sizeof(*tunables))); return -1; } *tunables = *(struct ctdb_tunable *)outdata.dptr; talloc_free(outdata.dptr); return 0; } /* add a public address to a node */ int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_control_ip_iface *pub) { TDB_DATA data; int32_t res; int ret; data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len; data.dptr = (unsigned char *)pub; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_ADD_PUBLIC_IP, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for add_public_ip failed\n")); return -1; } return 0; } /* delete a public address from a node */ int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_control_ip_iface *pub) { TDB_DATA data; int32_t res; int ret; data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len; data.dptr = (unsigned char *)pub; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_DEL_PUBLIC_IP, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for del_public_ip failed\n")); return -1; } return 0; } /* kill a tcp connection */ int ctdb_ctrl_killtcp(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_control_killtcp *killtcp) { TDB_DATA data; int32_t res; int ret; data.dsize = sizeof(struct ctdb_control_killtcp); data.dptr = (unsigned char *)killtcp; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_KILL_TCP, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for killtcp failed\n")); return -1; } return 0; } /* send a gratious arp */ int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, ctdb_sock_addr *addr, const char *ifname) { TDB_DATA data; int32_t res; int ret, len; struct ctdb_control_gratious_arp *gratious_arp; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); len = strlen(ifname)+1; gratious_arp = talloc_size(tmp_ctx, offsetof(struct ctdb_control_gratious_arp, iface) + len); CTDB_NO_MEMORY(ctdb, gratious_arp); gratious_arp->addr = *addr; gratious_arp->len = len; memcpy(&gratious_arp->iface[0], ifname, len); data.dsize = offsetof(struct ctdb_control_gratious_arp, iface) + len; data.dptr = (unsigned char *)gratious_arp; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SEND_GRATIOUS_ARP, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for gratious_arp failed\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } /* get a list of all tcp tickles that a node knows about for a particular vnn */ int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, ctdb_sock_addr *addr, struct ctdb_control_tcp_tickle_list **list) { int ret; TDB_DATA data, outdata; int32_t status; data.dptr = (uint8_t*)addr; data.dsize = sizeof(ctdb_sock_addr); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_TCP_TICKLE_LIST, 0, data, mem_ctx, &outdata, &status, NULL, NULL); if (ret != 0 || status != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get tcp tickles failed\n")); return -1; } *list = (struct ctdb_control_tcp_tickle_list *)outdata.dptr; return status; } /* register a server id */ int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb, struct timeval timeout, struct ctdb_server_id *id) { TDB_DATA data; int32_t res; int ret; data.dsize = sizeof(struct ctdb_server_id); data.dptr = (unsigned char *)id; ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_REGISTER_SERVER_ID, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for register server id failed\n")); return -1; } return 0; } /* unregister a server id */ int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb, struct timeval timeout, struct ctdb_server_id *id) { TDB_DATA data; int32_t res; int ret; data.dsize = sizeof(struct ctdb_server_id); data.dptr = (unsigned char *)id; ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_UNREGISTER_SERVER_ID, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for unregister server id failed\n")); return -1; } return 0; } /* check if a server id exists if a server id does exist, return *status == 1, otherwise *status == 0 */ int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_server_id *id, uint32_t *status) { TDB_DATA data; int32_t res; int ret; data.dsize = sizeof(struct ctdb_server_id); data.dptr = (unsigned char *)id; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_CHECK_SERVER_ID, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for check server id failed\n")); return -1; } if (res) { *status = 1; } else { *status = 0; } return 0; } /* get the list of server ids that are registered on a node */ int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_server_id_list **svid_list) { int ret; TDB_DATA outdata; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_SERVER_ID_LIST, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get_server_id_list failed\n")); return -1; } *svid_list = (struct ctdb_server_id_list *)talloc_steal(mem_ctx, outdata.dptr); return 0; } /* initialise the ctdb daemon for client applications NOTE: In current code the daemon does not fork. This is for testing purposes only and to simplify the code. */ struct ctdb_context *ctdb_init(struct event_context *ev) { int ret; struct ctdb_context *ctdb; ctdb = talloc_zero(ev, struct ctdb_context); if (ctdb == NULL) { DEBUG(DEBUG_ERR,(__location__ " talloc_zero failed.\n")); return NULL; } ctdb->ev = ev; ctdb->idr = idr_init(ctdb); /* Wrap early to exercise code. */ ctdb->lastid = INT_MAX-200; CTDB_NO_MEMORY_NULL(ctdb, ctdb->idr); ret = ctdb_set_socketname(ctdb, CTDB_PATH); if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_set_socketname failed.\n")); talloc_free(ctdb); return NULL; } ctdb->statistics.statistics_start_time = timeval_current(); return ctdb; } /* set some ctdb flags */ void ctdb_set_flags(struct ctdb_context *ctdb, unsigned flags) { ctdb->flags |= flags; } /* setup the local socket name */ int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname) { ctdb->daemon.name = talloc_strdup(ctdb, socketname); CTDB_NO_MEMORY(ctdb, ctdb->daemon.name); return 0; } const char *ctdb_get_socketname(struct ctdb_context *ctdb) { return ctdb->daemon.name; } /* return the pnn of this node */ uint32_t ctdb_get_pnn(struct ctdb_context *ctdb) { return ctdb->pnn; } /* get the uptime of a remote node */ struct ctdb_client_control_state * ctdb_ctrl_uptime_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode) { return ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_UPTIME, 0, tdb_null, mem_ctx, &timeout, NULL); } int ctdb_ctrl_uptime_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, struct ctdb_uptime **uptime) { int ret; int32_t res; TDB_DATA outdata; ret = ctdb_control_recv(ctdb, state, mem_ctx, &outdata, &res, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_uptime_recv failed\n")); return -1; } *uptime = (struct ctdb_uptime *)talloc_steal(mem_ctx, outdata.dptr); return 0; } int ctdb_ctrl_uptime(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_uptime **uptime) { struct ctdb_client_control_state *state; state = ctdb_ctrl_uptime_send(ctdb, mem_ctx, timeout, destnode); return ctdb_ctrl_uptime_recv(ctdb, mem_ctx, state, uptime); } /* send a control to execute the "recovered" event script on a node */ int ctdb_ctrl_end_recovery(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { int ret; int32_t status; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_END_RECOVERY, 0, tdb_null, NULL, NULL, &status, &timeout, NULL); if (ret != 0 || status != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for end_recovery failed\n")); return -1; } return 0; } /* callback for the async helpers used when sending the same control to multiple nodes in parallell. */ static void async_callback(struct ctdb_client_control_state *state) { struct client_async_data *data = talloc_get_type(state->async.private_data, struct client_async_data); struct ctdb_context *ctdb = talloc_get_type(state->ctdb, struct ctdb_context); int ret; TDB_DATA outdata; int32_t res = -1; uint32_t destnode = state->c->hdr.destnode; outdata.dsize = 0; outdata.dptr = NULL; /* one more node has responded with recmode data */ data->count--; /* if we failed to push the db, then return an error and let the main loop try again. */ if (state->state != CTDB_CONTROL_DONE) { if ( !data->dont_log_errors) { DEBUG(DEBUG_ERR,("Async operation failed with state %d, opcode:%u\n", state->state, data->opcode)); } data->fail_count++; if (state->state == CTDB_CONTROL_TIMEOUT) { res = -ETIME; } else { res = -1; } if (data->fail_callback) { data->fail_callback(ctdb, destnode, res, outdata, data->callback_data); } return; } state->async.fn = NULL; ret = ctdb_control_recv(ctdb, state, data, &outdata, &res, NULL); if ((ret != 0) || (res != 0)) { if ( !data->dont_log_errors) { DEBUG(DEBUG_ERR,("Async operation failed with ret=%d res=%d opcode=%u\n", ret, (int)res, data->opcode)); } data->fail_count++; if (data->fail_callback) { data->fail_callback(ctdb, destnode, res, outdata, data->callback_data); } } if ((ret == 0) && (data->callback != NULL)) { data->callback(ctdb, destnode, res, outdata, data->callback_data); } } void ctdb_client_async_add(struct client_async_data *data, struct ctdb_client_control_state *state) { /* set up the callback functions */ state->async.fn = async_callback; state->async.private_data = data; /* one more control to wait for to complete */ data->count++; } /* wait for up to the maximum number of seconds allowed or until all nodes we expect a response from has replied */ int ctdb_client_async_wait(struct ctdb_context *ctdb, struct client_async_data *data) { while (data->count > 0) { event_loop_once(ctdb->ev); } if (data->fail_count != 0) { if (!data->dont_log_errors) { DEBUG(DEBUG_ERR,("Async wait failed - fail_count=%u\n", data->fail_count)); } return -1; } return 0; } /* perform a simple control on the listed nodes The control cannot return data */ int ctdb_client_async_control(struct ctdb_context *ctdb, enum ctdb_controls opcode, uint32_t *nodes, uint64_t srvid, struct timeval timeout, bool dont_log_errors, TDB_DATA data, client_async_callback client_callback, client_async_callback fail_callback, void *callback_data) { struct client_async_data *async_data; struct ctdb_client_control_state *state; int j, num_nodes; async_data = talloc_zero(ctdb, struct client_async_data); CTDB_NO_MEMORY_FATAL(ctdb, async_data); async_data->dont_log_errors = dont_log_errors; async_data->callback = client_callback; async_data->fail_callback = fail_callback; async_data->callback_data = callback_data; async_data->opcode = opcode; num_nodes = talloc_get_size(nodes) / sizeof(uint32_t); /* loop over all nodes and send an async control to each of them */ for (j=0; jsize;i++) { if (vnn_map->map[i] == ctdb->pnn && !include_self) { continue; } num_nodes++; } nodes = talloc_array(mem_ctx, uint32_t, num_nodes); CTDB_NO_MEMORY_FATAL(ctdb, nodes); for (i=j=0;isize;i++) { if (vnn_map->map[i] == ctdb->pnn && !include_self) { continue; } nodes[j++] = vnn_map->map[i]; } return nodes; } /* Get list of nodes not including those with flags specified by mask. * If exclude_pnn is not -1 then exclude that pnn from the list. */ uint32_t *list_of_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *node_map, TALLOC_CTX *mem_ctx, uint32_t mask, int exclude_pnn) { int i, j, num_nodes; uint32_t *nodes; for (i=num_nodes=0;inum;i++) { if (node_map->nodes[i].flags & mask) { continue; } if (node_map->nodes[i].pnn == exclude_pnn) { continue; } num_nodes++; } nodes = talloc_array(mem_ctx, uint32_t, num_nodes); CTDB_NO_MEMORY_FATAL(ctdb, nodes); for (i=j=0;inum;i++) { if (node_map->nodes[i].flags & mask) { continue; } if (node_map->nodes[i].pnn == exclude_pnn) { continue; } nodes[j++] = node_map->nodes[i].pnn; } return nodes; } uint32_t *list_of_active_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *node_map, TALLOC_CTX *mem_ctx, bool include_self) { return list_of_nodes(ctdb, node_map, mem_ctx, NODE_FLAGS_INACTIVE, include_self ? -1 : ctdb->pnn); } uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *node_map, TALLOC_CTX *mem_ctx, bool include_self) { return list_of_nodes(ctdb, node_map, mem_ctx, NODE_FLAGS_DISCONNECTED, include_self ? -1 : ctdb->pnn); } /* this is used to test if a pnn lock exists and if it exists will return the number of connections that pnn has reported or -1 if that recovery daemon is not running. */ int ctdb_read_pnn_lock(int fd, int32_t pnn) { struct flock lock; char c; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = pnn; lock.l_len = 1; lock.l_pid = 0; if (fcntl(fd, F_GETLK, &lock) != 0) { DEBUG(DEBUG_ERR, (__location__ " F_GETLK failed with %s\n", strerror(errno))); return -1; } if (lock.l_type == F_UNLCK) { return -1; } if (pread(fd, &c, 1, pnn) == -1) { DEBUG(DEBUG_CRIT,(__location__ " failed read pnn count - %s\n", strerror(errno))); return -1; } return c; } /* get capabilities of a remote node */ struct ctdb_client_control_state * ctdb_ctrl_getcapabilities_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode) { return ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_GET_CAPABILITIES, 0, tdb_null, mem_ctx, &timeout, NULL); } int ctdb_ctrl_getcapabilities_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *capabilities) { int ret; int32_t res; TDB_DATA outdata; ret = ctdb_control_recv(ctdb, state, mem_ctx, &outdata, &res, NULL); if ( (ret != 0) || (res != 0) ) { DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_getcapabilities_recv failed\n")); return -1; } if (capabilities) { *capabilities = *((uint32_t *)outdata.dptr); } return 0; } int ctdb_ctrl_getcapabilities(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *capabilities) { struct ctdb_client_control_state *state; TALLOC_CTX *tmp_ctx = talloc_new(NULL); int ret; state = ctdb_ctrl_getcapabilities_send(ctdb, tmp_ctx, timeout, destnode); ret = ctdb_ctrl_getcapabilities_recv(ctdb, tmp_ctx, state, capabilities); talloc_free(tmp_ctx); return ret; } struct server_id { uint64_t pid; uint32_t task_id; uint32_t vnn; uint64_t unique_id; }; static struct server_id server_id_get(struct ctdb_context *ctdb, uint32_t reqid) { struct server_id id; id.pid = getpid(); id.task_id = reqid; id.vnn = ctdb_get_pnn(ctdb); id.unique_id = id.vnn; id.unique_id = (id.unique_id << 32) | reqid; return id; } static bool server_id_equal(struct server_id *id1, struct server_id *id2) { if (id1->pid != id2->pid) { return false; } if (id1->task_id != id2->task_id) { return false; } if (id1->vnn != id2->vnn) { return false; } if (id1->unique_id != id2->unique_id) { return false; } return true; } static bool server_id_exists(struct ctdb_context *ctdb, struct server_id *id) { struct ctdb_server_id sid; int ret; uint32_t result; sid.type = SERVER_TYPE_SAMBA; sid.pnn = id->vnn; sid.server_id = id->pid; ret = ctdb_ctrl_check_server_id(ctdb, timeval_current_ofs(3,0), id->vnn, &sid, &result); if (ret != 0) { /* If control times out, assume server_id exists. */ return true; } if (result) { return true; } return false; } enum g_lock_type { G_LOCK_READ = 0, G_LOCK_WRITE = 1, }; struct g_lock_rec { enum g_lock_type type; struct server_id id; }; struct g_lock_recs { unsigned int num; struct g_lock_rec *lock; }; static bool g_lock_parse(TALLOC_CTX *mem_ctx, TDB_DATA data, struct g_lock_recs **locks) { struct g_lock_recs *recs; recs = talloc_zero(mem_ctx, struct g_lock_recs); if (recs == NULL) { return false; } if (data.dsize == 0) { goto done; } if (data.dsize % sizeof(struct g_lock_rec) != 0) { DEBUG(DEBUG_ERR, (__location__ "invalid data size %lu in g_lock record\n", (unsigned long)data.dsize)); talloc_free(recs); return false; } recs->num = data.dsize / sizeof(struct g_lock_rec); recs->lock = talloc_memdup(mem_ctx, data.dptr, data.dsize); if (recs->lock == NULL) { talloc_free(recs); return false; } done: if (locks != NULL) { *locks = recs; } return true; } static bool g_lock_lock(TALLOC_CTX *mem_ctx, struct ctdb_db_context *ctdb_db, const char *keyname, uint32_t reqid) { TDB_DATA key, data; struct ctdb_record_handle *h; struct g_lock_recs *locks; struct server_id id; struct timeval t_start; int i; key.dptr = (uint8_t *)discard_const(keyname); key.dsize = strlen(keyname) + 1; t_start = timeval_current(); again: /* Keep trying for an hour. */ if (timeval_elapsed(&t_start) > 3600) { return false; } h = ctdb_fetch_lock(ctdb_db, mem_ctx, key, &data); if (h == NULL) { return false; } if (!g_lock_parse(h, data, &locks)) { DEBUG(DEBUG_ERR, ("g_lock: error parsing locks\n")); talloc_free(data.dptr); talloc_free(h); return false; } talloc_free(data.dptr); id = server_id_get(ctdb_db->ctdb, reqid); i = 0; while (i < locks->num) { if (server_id_equal(&locks->lock[i].id, &id)) { /* Internal error */ talloc_free(h); return false; } if (!server_id_exists(ctdb_db->ctdb, &locks->lock[i].id)) { if (i < locks->num-1) { locks->lock[i] = locks->lock[locks->num-1]; } locks->num--; continue; } /* This entry is locked. */ DEBUG(DEBUG_INFO, ("g_lock: lock already granted for " "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n", (unsigned long long)id.pid, id.task_id, id.vnn, (unsigned long long)id.unique_id)); talloc_free(h); goto again; } locks->lock = talloc_realloc(locks, locks->lock, struct g_lock_rec, locks->num+1); if (locks->lock == NULL) { talloc_free(h); return false; } locks->lock[locks->num].type = G_LOCK_WRITE; locks->lock[locks->num].id = id; locks->num++; data.dptr = (uint8_t *)locks->lock; data.dsize = locks->num * sizeof(struct g_lock_rec); if (ctdb_record_store(h, data) != 0) { DEBUG(DEBUG_ERR, ("g_lock: failed to write transaction lock for " "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n", (unsigned long long)id.pid, id.task_id, id.vnn, (unsigned long long)id.unique_id)); talloc_free(h); return false; } DEBUG(DEBUG_INFO, ("g_lock: lock granted for " "pid=0x%llx taskid=%x vnn=%d id=0x%llx\n", (unsigned long long)id.pid, id.task_id, id.vnn, (unsigned long long)id.unique_id)); talloc_free(h); return true; } static bool g_lock_unlock(TALLOC_CTX *mem_ctx, struct ctdb_db_context *ctdb_db, const char *keyname, uint32_t reqid) { TDB_DATA key, data; struct ctdb_record_handle *h; struct g_lock_recs *locks; struct server_id id; int i; bool found = false; key.dptr = (uint8_t *)discard_const(keyname); key.dsize = strlen(keyname) + 1; h = ctdb_fetch_lock(ctdb_db, mem_ctx, key, &data); if (h == NULL) { return false; } if (!g_lock_parse(h, data, &locks)) { DEBUG(DEBUG_ERR, ("g_lock: error parsing locks\n")); talloc_free(data.dptr); talloc_free(h); return false; } talloc_free(data.dptr); id = server_id_get(ctdb_db->ctdb, reqid); for (i=0; inum; i++) { if (server_id_equal(&locks->lock[i].id, &id)) { if (i < locks->num-1) { locks->lock[i] = locks->lock[locks->num-1]; } locks->num--; found = true; break; } } if (!found) { DEBUG(DEBUG_ERR, ("g_lock: lock not found\n")); talloc_free(h); return false; } data.dptr = (uint8_t *)locks->lock; data.dsize = locks->num * sizeof(struct g_lock_rec); if (ctdb_record_store(h, data) != 0) { talloc_free(h); return false; } talloc_free(h); return true; } struct ctdb_transaction_handle { struct ctdb_db_context *ctdb_db; struct ctdb_db_context *g_lock_db; char *lock_name; uint32_t reqid; /* * we store reads and writes done under a transaction: * - one list stores both reads and writes (m_all) * - the other just writes (m_write) */ struct ctdb_marshall_buffer *m_all; struct ctdb_marshall_buffer *m_write; }; static int ctdb_transaction_destructor(struct ctdb_transaction_handle *h) { g_lock_unlock(h, h->g_lock_db, h->lock_name, h->reqid); ctdb_reqid_remove(h->ctdb_db->ctdb, h->reqid); return 0; } /** * start a transaction on a database */ struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx) { struct ctdb_transaction_handle *h; struct ctdb_server_id id; h = talloc_zero(mem_ctx, struct ctdb_transaction_handle); if (h == NULL) { DEBUG(DEBUG_ERR, (__location__ " memory allocation error\n")); return NULL; } h->ctdb_db = ctdb_db; h->lock_name = talloc_asprintf(h, "transaction_db_0x%08x", (unsigned int)ctdb_db->db_id); if (h->lock_name == NULL) { DEBUG(DEBUG_ERR, (__location__ " talloc asprintf failed\n")); talloc_free(h); return NULL; } h->g_lock_db = ctdb_attach(h->ctdb_db->ctdb, timeval_current_ofs(3,0), "g_lock.tdb", false, 0); if (!h->g_lock_db) { DEBUG(DEBUG_ERR, (__location__ " unable to attach to g_lock.tdb\n")); talloc_free(h); return NULL; } id.type = SERVER_TYPE_SAMBA; id.pnn = ctdb_get_pnn(ctdb_db->ctdb); id.server_id = getpid(); if (ctdb_ctrl_register_server_id(ctdb_db->ctdb, timeval_current_ofs(3,0), &id) != 0) { DEBUG(DEBUG_ERR, (__location__ " unable to register server id\n")); talloc_free(h); return NULL; } h->reqid = ctdb_reqid_new(h->ctdb_db->ctdb, h); if (!g_lock_lock(h, h->g_lock_db, h->lock_name, h->reqid)) { DEBUG(DEBUG_ERR, (__location__ " Error locking g_lock.tdb\n")); talloc_free(h); return NULL; } talloc_set_destructor(h, ctdb_transaction_destructor); return h; } /** * fetch a record inside a transaction */ int ctdb_transaction_fetch(struct ctdb_transaction_handle *h, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data) { struct ctdb_ltdb_header header; int ret; ZERO_STRUCT(header); ret = ctdb_ltdb_fetch(h->ctdb_db, key, &header, mem_ctx, data); if (ret == -1 && header.dmaster == (uint32_t)-1) { /* record doesn't exist yet */ *data = tdb_null; ret = 0; } if (ret != 0) { return ret; } h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 1, key, NULL, *data); if (h->m_all == NULL) { DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n")); return -1; } return 0; } /** * stores a record inside a transaction */ int ctdb_transaction_store(struct ctdb_transaction_handle *h, TDB_DATA key, TDB_DATA data) { TALLOC_CTX *tmp_ctx = talloc_new(h); struct ctdb_ltdb_header header; TDB_DATA olddata; int ret; /* we need the header so we can update the RSN */ ret = ctdb_ltdb_fetch(h->ctdb_db, key, &header, tmp_ctx, &olddata); if (ret == -1 && header.dmaster == (uint32_t)-1) { /* the record doesn't exist - create one with us as dmaster. This is only safe because we are in a transaction and this is a persistent database */ ZERO_STRUCT(header); } else if (ret != 0) { DEBUG(DEBUG_ERR,(__location__ " Failed to fetch record\n")); talloc_free(tmp_ctx); return ret; } if (data.dsize == olddata.dsize && memcmp(data.dptr, olddata.dptr, data.dsize) == 0 && header.rsn != 0) { /* save writing the same data */ talloc_free(tmp_ctx); return 0; } header.dmaster = h->ctdb_db->ctdb->pnn; header.rsn++; h->m_all = ctdb_marshall_add(h, h->m_all, h->ctdb_db->db_id, 0, key, NULL, data); if (h->m_all == NULL) { DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n")); talloc_free(tmp_ctx); return -1; } h->m_write = ctdb_marshall_add(h, h->m_write, h->ctdb_db->db_id, 0, key, &header, data); if (h->m_write == NULL) { DEBUG(DEBUG_ERR,(__location__ " Failed to add to marshalling record\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } static int ctdb_fetch_db_seqnum(struct ctdb_db_context *ctdb_db, uint64_t *seqnum) { const char *keyname = CTDB_DB_SEQNUM_KEY; TDB_DATA key, data; struct ctdb_ltdb_header header; int ret; key.dptr = (uint8_t *)discard_const(keyname); key.dsize = strlen(keyname) + 1; ret = ctdb_ltdb_fetch(ctdb_db, key, &header, ctdb_db, &data); if (ret != 0) { *seqnum = 0; return 0; } if (data.dsize == 0) { *seqnum = 0; return 0; } if (data.dsize != sizeof(*seqnum)) { DEBUG(DEBUG_ERR, (__location__ " Invalid data recived len=%zi\n", data.dsize)); talloc_free(data.dptr); return -1; } *seqnum = *(uint64_t *)data.dptr; talloc_free(data.dptr); return 0; } static int ctdb_store_db_seqnum(struct ctdb_transaction_handle *h, uint64_t seqnum) { const char *keyname = CTDB_DB_SEQNUM_KEY; TDB_DATA key, data; key.dptr = (uint8_t *)discard_const(keyname); key.dsize = strlen(keyname) + 1; data.dptr = (uint8_t *)&seqnum; data.dsize = sizeof(seqnum); return ctdb_transaction_store(h, key, data); } /** * commit a transaction */ int ctdb_transaction_commit(struct ctdb_transaction_handle *h) { int ret; uint64_t old_seqnum, new_seqnum; int32_t status; struct timeval timeout; if (h->m_write == NULL) { /* no changes were made */ talloc_free(h); return 0; } ret = ctdb_fetch_db_seqnum(h->ctdb_db, &old_seqnum); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " failed to fetch db sequence number\n")); ret = -1; goto done; } new_seqnum = old_seqnum + 1; ret = ctdb_store_db_seqnum(h, new_seqnum); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " failed to store db sequence number\n")); ret = -1; goto done; } again: timeout = timeval_current_ofs(3,0); ret = ctdb_control(h->ctdb_db->ctdb, CTDB_CURRENT_NODE, h->ctdb_db->db_id, CTDB_CONTROL_TRANS3_COMMIT, 0, ctdb_marshall_finish(h->m_write), NULL, NULL, &status, &timeout, NULL); if (ret != 0 || status != 0) { /* * TRANS3_COMMIT control will only fail if recovery has been * triggered. Check if the database has been updated or not. */ ret = ctdb_fetch_db_seqnum(h->ctdb_db, &new_seqnum); if (ret != 0) { DEBUG(DEBUG_ERR, (__location__ " failed to fetch db sequence number\n")); goto done; } if (new_seqnum == old_seqnum) { /* Database not yet updated, try again */ goto again; } if (new_seqnum != (old_seqnum + 1)) { DEBUG(DEBUG_ERR, (__location__ " new seqnum [%llu] != old seqnum [%llu] + 1\n", (long long unsigned)new_seqnum, (long long unsigned)old_seqnum)); ret = -1; goto done; } } ret = 0; done: talloc_free(h); return ret; } /** * cancel a transaction */ int ctdb_transaction_cancel(struct ctdb_transaction_handle *h) { talloc_free(h); return 0; } /* recovery daemon ping to main daemon */ int ctdb_ctrl_recd_ping(struct ctdb_context *ctdb) { int ret; int32_t res; ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_RECD_PING, 0, tdb_null, ctdb, NULL, &res, NULL, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("Failed to send recd ping\n")); return -1; } return 0; } /* When forking the main daemon and the child process needs to connect * back to the daemon as a client process, this function can be used * to change the ctdb context from daemon into client mode. The child * process must be created using ctdb_fork() and not fork() - * ctdb_fork() does some necessary housekeeping. */ int switch_from_server_to_client(struct ctdb_context *ctdb, const char *fmt, ...) { int ret; va_list ap; /* Add extra information so we can identify this in the logs */ va_start(ap, fmt); debug_extra = talloc_strdup_append(talloc_vasprintf(NULL, fmt, ap), ":"); va_end(ap); /* get a new event context */ ctdb->ev = event_context_init(ctdb); tevent_loop_allow_nesting(ctdb->ev); /* Connect to main CTDB daemon */ ret = ctdb_socket_connect(ctdb); if (ret != 0) { DEBUG(DEBUG_ALERT, (__location__ " Failed to init ctdb client\n")); return -1; } ctdb->can_send_controls = true; return 0; } /* get the status of running the monitor eventscripts: NULL means never run. */ int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, enum ctdb_eventscript_call type, struct ctdb_scripts_wire **scripts) { int ret; TDB_DATA outdata, indata; int32_t res; uint32_t uinttype = type; indata.dptr = (uint8_t *)&uinttype; indata.dsize = sizeof(uinttype); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS, 0, indata, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getscriptstatus failed ret:%d res:%d\n", ret, res)); return -1; } if (outdata.dsize == 0) { *scripts = NULL; } else { *scripts = (struct ctdb_scripts_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize); talloc_free(outdata.dptr); } return 0; } /* tell the main daemon how long it took to lock the reclock file */ int ctdb_ctrl_report_recd_lock_latency(struct ctdb_context *ctdb, struct timeval timeout, double latency) { int ret; int32_t res; TDB_DATA data; data.dptr = (uint8_t *)&latency; data.dsize = sizeof(latency); ret = ctdb_control(ctdb, CTDB_CURRENT_NODE, 0, CTDB_CONTROL_RECD_RECLOCK_LATENCY, 0, data, ctdb, NULL, &res, NULL, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("Failed to send recd reclock latency\n")); return -1; } return 0; } /* get the name of the reclock file */ int ctdb_ctrl_getreclock(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const char **name) { int ret; int32_t res; TDB_DATA data; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_RECLOCK_FILE, 0, tdb_null, mem_ctx, &data, &res, &timeout, NULL); if (ret != 0 || res != 0) { return -1; } if (data.dsize == 0) { *name = NULL; } else { *name = talloc_strdup(mem_ctx, discard_const(data.dptr)); } talloc_free(data.dptr); return 0; } /* set the reclock filename for a node */ int ctdb_ctrl_setreclock(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *reclock) { int ret; TDB_DATA data; int32_t res; if (reclock == NULL) { data.dsize = 0; data.dptr = NULL; } else { data.dsize = strlen(reclock) + 1; data.dptr = discard_const(reclock); } ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_RECLOCK_FILE, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setreclock failed\n")); return -1; } return 0; } /* stop a node */ int ctdb_ctrl_stop_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { int ret; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_STOP_NODE, 0, tdb_null, ctdb, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("Failed to stop node\n")); return -1; } return 0; } /* continue a node */ int ctdb_ctrl_continue_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode) { int ret; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_CONTINUE_NODE, 0, tdb_null, ctdb, NULL, NULL, &timeout, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to continue node\n")); return -1; } return 0; } /* set the natgw state for a node */ int ctdb_ctrl_setnatgwstate(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t natgwstate) { int ret; TDB_DATA data; int32_t res; data.dsize = sizeof(natgwstate); data.dptr = (uint8_t *)&natgwstate; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_NATGWSTATE, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setnatgwstate failed\n")); return -1; } return 0; } /* set the lmaster role for a node */ int ctdb_ctrl_setlmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t lmasterrole) { int ret; TDB_DATA data; int32_t res; data.dsize = sizeof(lmasterrole); data.dptr = (uint8_t *)&lmasterrole; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_LMASTERROLE, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setlmasterrole failed\n")); return -1; } return 0; } /* set the recmaster role for a node */ int ctdb_ctrl_setrecmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmasterrole) { int ret; TDB_DATA data; int32_t res; data.dsize = sizeof(recmasterrole); data.dptr = (uint8_t *)&recmasterrole; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_RECMASTERROLE, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for setrecmasterrole failed\n")); return -1; } return 0; } /* enable an eventscript */ int ctdb_ctrl_enablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script) { int ret; TDB_DATA data; int32_t res; data.dsize = strlen(script) + 1; data.dptr = discard_const(script); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_ENABLE_SCRIPT, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for enablescript failed\n")); return -1; } return 0; } /* disable an eventscript */ int ctdb_ctrl_disablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script) { int ret; TDB_DATA data; int32_t res; data.dsize = strlen(script) + 1; data.dptr = discard_const(script); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_DISABLE_SCRIPT, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for disablescript failed\n")); return -1; } return 0; } int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_ban_time *bantime) { int ret; TDB_DATA data; int32_t res; data.dsize = sizeof(*bantime); data.dptr = (uint8_t *)bantime; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_BAN_STATE, 0, data, NULL, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set ban state failed\n")); return -1; } return 0; } int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_ban_time **bantime) { int ret; TDB_DATA outdata; int32_t res; TALLOC_CTX *tmp_ctx = talloc_new(NULL); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_BAN_STATE, 0, tdb_null, tmp_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set ban state failed\n")); talloc_free(tmp_ctx); return -1; } *bantime = (struct ctdb_ban_time *)talloc_steal(mem_ctx, outdata.dptr); talloc_free(tmp_ctx); return 0; } int ctdb_ctrl_set_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_db_priority *db_prio) { int ret; int32_t res; TDB_DATA data; TALLOC_CTX *tmp_ctx = talloc_new(NULL); data.dptr = (uint8_t*)db_prio; data.dsize = sizeof(*db_prio); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SET_DB_PRIORITY, 0, data, tmp_ctx, NULL, &res, &timeout, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set_db_priority failed\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t db_id, uint32_t *priority) { int ret; int32_t res; TDB_DATA data; TALLOC_CTX *tmp_ctx = talloc_new(NULL); data.dptr = (uint8_t*)&db_id; data.dsize = sizeof(db_id); ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_DB_PRIORITY, 0, data, tmp_ctx, NULL, &res, &timeout, NULL); if (ret != 0 || res < 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get_db_priority failed\n")); talloc_free(tmp_ctx); return -1; } if (priority) { *priority = res; } talloc_free(tmp_ctx); return 0; } int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_statistics_wire **stats) { int ret; TDB_DATA outdata; int32_t res; ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_GET_STAT_HISTORY, 0, tdb_null, mem_ctx, &outdata, &res, &timeout, NULL); if (ret != 0 || res != 0 || outdata.dsize == 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_control for getstathistory failed ret:%d res:%d\n", ret, res)); return -1; } *stats = (struct ctdb_statistics_wire *)talloc_memdup(mem_ctx, outdata.dptr, outdata.dsize); talloc_free(outdata.dptr); return 0; } struct ctdb_ltdb_header *ctdb_header_from_record_handle(struct ctdb_record_handle *h) { if (h == NULL) { return NULL; } return &h->header; } struct ctdb_client_control_state * ctdb_ctrl_updaterecord_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data) { struct ctdb_client_control_state *handle; struct ctdb_marshall_buffer *m; struct ctdb_rec_data *rec; TDB_DATA outdata; m = talloc_zero(mem_ctx, struct ctdb_marshall_buffer); if (m == NULL) { DEBUG(DEBUG_ERR, ("Failed to allocate marshall buffer for update record\n")); return NULL; } m->db_id = ctdb_db->db_id; rec = ctdb_marshall_record(m, 0, key, header, data); if (rec == NULL) { DEBUG(DEBUG_ERR,("Failed to marshall record for update record\n")); talloc_free(m); return NULL; } m = talloc_realloc_size(mem_ctx, m, rec->length + offsetof(struct ctdb_marshall_buffer, data)); if (m == NULL) { DEBUG(DEBUG_CRIT,(__location__ " Failed to expand recdata\n")); talloc_free(m); return NULL; } m->count++; memcpy((uint8_t *)m + offsetof(struct ctdb_marshall_buffer, data), rec, rec->length); outdata.dptr = (uint8_t *)m; outdata.dsize = talloc_get_size(m); handle = ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_UPDATE_RECORD, 0, outdata, mem_ctx, &timeout, NULL); talloc_free(m); return handle; } int ctdb_ctrl_updaterecord_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state) { int ret; int32_t res; ret = ctdb_control_recv(ctdb, state, state, NULL, &res, NULL); if ( (ret != 0) || (res != 0) ){ DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_update_record_recv failed\n")); return -1; } return 0; } int ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data) { struct ctdb_client_control_state *state; state = ctdb_ctrl_updaterecord_send(ctdb, mem_ctx, timeout, destnode, ctdb_db, key, header, data); return ctdb_ctrl_updaterecord_recv(ctdb, state); } /* set a database to be readonly */ struct ctdb_client_control_state * ctdb_ctrl_set_db_readonly_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid) { TDB_DATA data; data.dptr = (uint8_t *)&dbid; data.dsize = sizeof(dbid); return ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_SET_DB_READONLY, 0, data, ctdb, NULL, NULL); } int ctdb_ctrl_set_db_readonly_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state) { int ret; int32_t res; ret = ctdb_control_recv(ctdb, state, ctdb, NULL, &res, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_set_db_readonly_recv failed ret:%d res:%d\n", ret, res)); return -1; } return 0; } int ctdb_ctrl_set_db_readonly(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid) { struct ctdb_client_control_state *state; state = ctdb_ctrl_set_db_readonly_send(ctdb, destnode, dbid); return ctdb_ctrl_set_db_readonly_recv(ctdb, state); } /* set a database to be sticky */ struct ctdb_client_control_state * ctdb_ctrl_set_db_sticky_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid) { TDB_DATA data; data.dptr = (uint8_t *)&dbid; data.dsize = sizeof(dbid); return ctdb_control_send(ctdb, destnode, 0, CTDB_CONTROL_SET_DB_STICKY, 0, data, ctdb, NULL, NULL); } int ctdb_ctrl_set_db_sticky_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state) { int ret; int32_t res; ret = ctdb_control_recv(ctdb, state, ctdb, NULL, &res, NULL); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_set_db_sticky_recv failed ret:%d res:%d\n", ret, res)); return -1; } return 0; } int ctdb_ctrl_set_db_sticky(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid) { struct ctdb_client_control_state *state; state = ctdb_ctrl_set_db_sticky_send(ctdb, destnode, dbid); return ctdb_ctrl_set_db_sticky_recv(ctdb, state); } ctdb-2.5.1.dfsg/config.guess0000644000175000017500000013036112245023514015546 0ustar mathieumathieu#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-06-10' # This file 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 3 of the License, or # (at your option) any later version. # # This program 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 this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ctdb-2.5.1.dfsg/include/0000755000175000017500000000000012245332454014656 5ustar mathieumathieuctdb-2.5.1.dfsg/include/ctdb_typesafe_cb.h0000644000175000017500000001535212245023514020307 0ustar mathieumathieu#ifndef CCAN_CAST_IF_TYPE_H #define CCAN_CAST_IF_TYPE_H #if (__GNUC__ >= 3) #define HAVE_TYPEOF 1 #define HAVE_BUILTIN_CHOOSE_EXPR 1 #define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1 #endif #if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P /** * cast_if_type - only cast an expression if test matches a given type * @desttype: the type to cast to * @expr: the expression to cast * @test: the expression to test * @oktype: the type we allow * * This macro is used to create functions which allow multiple types. * The result of this macro is used somewhere that a @desttype type is * expected: if @expr was of type @oktype, it will be cast to * @desttype type. As a result, if @expr is any type other than * @oktype or @desttype, a compiler warning will be issued. * * This macro can be used in static initializers. * * This is merely useful for warnings: if the compiler does not * support the primitives required for cast_if_type(), it becomes an * unconditional cast, and the @test and @oktype argument is not used. In * particular, this means that @oktype can be a type which uses * the "typeof": it will not be evaluated if typeof is not supported. * * Example: * // We can take either an unsigned long or a void *. * void _set_some_value(void *val); * #define set_some_value(e) \ * _set_some_value(cast_if_type(void *, (e), (e), unsigned long)) */ #define cast_if_type(desttype, expr, test, oktype) \ __builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(test):0), oktype), \ (desttype)(expr), (expr)) #else #define cast_if_type(desttype, expr, test, oktype) ((desttype)(expr)) #endif /** * cast_if_any - only cast an expression if it is one of the three given types * @desttype: the type to cast to * @expr: the expression to cast * @test: the expression to test * @ok1: the first type we allow * @ok2: the second type we allow * @ok3: the third type we allow * * This is a convenient wrapper for multiple cast_if_type() calls. You can * chain them inside each other (ie. use cast_if_any() for expr) if you need * more than 3 arguments. * * Example: * // We can take either a long, unsigned long, void * or a const void *. * void _set_some_value(void *val); * #define set_some_value(expr) \ * _set_some_value(cast_if_any(void *, (expr), (expr), \ * long, unsigned long, const void *)) */ #define cast_if_any(desttype, expr, test, ok1, ok2, ok3) \ cast_if_type(desttype, \ cast_if_type(desttype, \ cast_if_type(desttype, (expr), (test), ok1), \ ok2), \ ok3) /** * typesafe_cb - cast a callback function if it matches the arg * @rtype: the return type of the callback function * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * * If a callback function takes a single argument, this macro does * appropriate casts to a function which takes a single void * argument if the * callback provided matches the @arg (or a const or volatile version). * * It is assumed that @arg is of pointer type: usually @arg is passed * or assigned to a void * elsewhere anyway. * * Example: * void _register_callback(void (*fn)(void *arg), void *arg); * #define register_callback(fn, arg) \ * _register_callback(typesafe_cb(void, (fn), (arg)), (arg)) */ #define typesafe_cb(rtype, fn, arg) \ cast_if_type(rtype (*)(void *), (fn), (fn)(arg), rtype) /** * typesafe_cb_const - cast a const callback function if it matches the arg * @rtype: the return type of the callback function * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * * If a callback function takes a single argument, this macro does appropriate * casts to a function which takes a single const void * argument if the * callback provided matches the @arg. * * It is assumed that @arg is of pointer type: usually @arg is passed * or assigned to a void * elsewhere anyway. * * Example: * void _register_callback(void (*fn)(const void *arg), const void *arg); * #define register_callback(fn, arg) \ * _register_callback(typesafe_cb_const(void, (fn), (arg)), (arg)) */ #define typesafe_cb_const(rtype, fn, arg) \ sizeof((fn)((const void *)0)), \ cast_if_type(rtype (*)(const void *), \ (fn), (fn)(arg), rtype (*)(typeof(arg))) /** * typesafe_cb_preargs - cast a callback function if it matches the arg * @rtype: the return type of the callback function * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * * This is a version of typesafe_cb() for callbacks that take other arguments * before the @arg. * * Example: * void _register_callback(void (*fn)(int, void *arg), void *arg); * #define register_callback(fn, arg) \ * _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\ * (arg)) */ #define typesafe_cb_preargs(rtype, fn, arg, ...) \ cast_if_type(rtype (*)(__VA_ARGS__, void *), (fn), (fn), \ rtype (*)(__VA_ARGS__, typeof(arg))) /** * typesafe_cb_postargs - cast a callback function if it matches the arg * @rtype: the return type of the callback function * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * * This is a version of typesafe_cb() for callbacks that take other arguments * after the @arg. * * Example: * void _register_callback(void (*fn)(void *arg, int), void *arg); * #define register_callback(fn, arg) \ * _register_callback(typesafe_cb_postargs(void, (fn), (arg), int),\ * (arg)) */ #define typesafe_cb_postargs(rtype, fn, arg, ...) \ cast_if_type(rtype (*)(void *, __VA_ARGS__), (fn), (fn), \ rtype (*)(typeof(arg), __VA_ARGS__)) /** * typesafe_cb_cmp - cast a compare function if it matches the arg * @rtype: the return type of the callback function * @fn: the callback function to cast * @arg: the (pointer) argument(s) to hand to the compare function. * * If a callback function takes two matching-type arguments, this macro does * appropriate casts to a function which takes two const void * arguments if * the callback provided takes two a const pointers to @arg. * * It is assumed that @arg is of pointer type: usually @arg is passed * or assigned to a void * elsewhere anyway. Note also that the type * arg points to must be defined. * * Example: * void _my_qsort(void *base, size_t nmemb, size_t size, * int (*cmp)(const void *, const void *)); * #define my_qsort(base, nmemb, cmpfn) \ * _my_qsort((base), (nmemb), sizeof(*(base)), \ * typesafe_cb_cmp(int, (cmpfn), (base)), (arg)) */ #define typesafe_cb_cmp(rtype, cmpfn, arg) \ cast_if_type(rtype (*)(const void *, const void *), (cmpfn), \ rtype (*)(const typeof(*arg)*, const typeof(*arg)*)) #endif /* CCAN_CAST_IF_TYPE_H */ ctdb-2.5.1.dfsg/include/ctdb.h0000644000175000017500000012431412245023514015742 0ustar mathieumathieu/* ctdb database library Copyright (C) Ronnie sahlberg 2010 Copyright (C) Rusty Russell 2010 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #ifndef _CTDB_H #define _CTDB_H #include #include #include #include #include #include #include #include /** * ctdb - a library for accessing tdbs controlled by ctdbd * * ctdbd (clustered tdb daemon) is a daemon designed to syncronize TDB * databases across a cluster. Using this library, you can communicate with * the daemon to access the databases, pass messages across the cluster, and * control the daemon itself. * * The general API is event-driven and asynchronous: you call the * *_send functions, supplying callbacks, then when the ctdbd file * descriptor is usable, call ctdb_service() to perform read from it * and call your callbacks, which use the *_recv functions to unpack * the replies from ctdbd. * * There is also a synchronous wrapper for each function for trivial * programs; these can be found in the section marked "Synchronous API". */ /** * ctdb_log_fn_t - logging function for ctdbd * @log_priv: private (typesafe) arg via ctdb_connect * @severity: syslog-style severity * @format: printf-style format string. * @ap: arguments for formatting. * * The severity passed to log() are as per syslog(3). In particular, * LOG_DEBUG is used for tracing, LOG_WARNING is used for unusual * conditions which don't necessarily return an error through the API, * LOG_ERR is used for errors such as lost communication with ctdbd or * out-of-memory, LOG_ALERT is used for library usage bugs, LOG_CRIT is * used for libctdb internal consistency checks. * * The log() function can be typesafe: the @log_priv arg to * ctdb_donnect and signature of log() should match. */ typedef void (*ctdb_log_fn_t)(void *log_priv, int severity, const char *format, va_list ap); /** * ctdb_connect - connect to ctdb using the specified domain socket. * @addr: the socket address, or NULL for default * @log: the logging function * @log_priv: the private argument to the logging function. * * Returns a ctdb context if successful or NULL. Use ctdb_disconnect() to * release the returned ctdb_connection when finished. * * See Also: * ctdb_log_fn_t, ctdb_log_file() */ struct ctdb_connection *ctdb_connect(const char *addr, ctdb_log_fn_t log_fn, void *log_priv); /** * ctdb_log_file - example logging function * * Logs everything at priority LOG_WARNING or above to the file given (via * the log_priv argument, usually stderr). */ void ctdb_log_file(FILE *, int, const char *, va_list); /** * ctdb_log_level - level at which to call logging function * * This variable globally controls filtering on the logging function. * It is initialized to LOG_WARNING, meaning that strange but nonfatal * events, as well as errors and API misuses are reported. * * Set it to LOG_DEBUG to receive all messages. */ extern int ctdb_log_level; /** * ctdb_disconnect - close down a connection to ctdbd. * @ctdb: the ctdb connectio returned from ctdb_connect. * * The @ctdb arg will be freed by this call, and must not be used again. */ void ctdb_disconnect(struct ctdb_connection *ctdb); /*** * * Asynchronous API * ***/ /** * ctdb_num_active - get the number of active commands * @ctdb: the ctdb_connection from ctdb_connect. * * This command can be used to find the number of active commands we have * issued. An active command is a command we have queued, or sent * to the ctdb daemon but which we have not yet received a reply to. * * See Also: * ctdb_num_in_flight(), ctdb_num_out_queue() */ int ctdb_num_active(struct ctdb_connection *ctdb); /** * ctdb_num_in_flight - get the number of commands in flight. * @ctdb: the ctdb_connection from ctdb_connect. * * This command can be used to find the number of commands we have * sent to the ctdb daemon to which we have not yet received/processed * the reply. * * See Also: * ctdb_num_out_queue(), ctdb_num_active() */ int ctdb_num_in_flight(struct ctdb_connection *ctdb); /** * ctdb_num_out_queue - get the number of commands in the out queue * @ctdb: the ctdb_connection from ctdb_connect. * * This command can be used to find the number of commands we have * queued for delivery to the ctdb daemon but have not yet been * written to the domain socket. * * See Also: * ctdb_num_in_flight(), ctdb_num_active() */ int ctdb_num_out_queue(struct ctdb_connection *ctdb); /** * ctdb_get_fd - get the filedescriptor to select/poll on * @ctdb: the ctdb_connection from ctdb_connect. * * By using poll or select on this file descriptor, you will know when to call * ctdb_service(). * * See Also: * ctdb_which_events(), ctdb_service() */ int ctdb_get_fd(struct ctdb_connection *ctdb); /** * ctdb_which_events - determine which events ctdb_service wants to see * @ctdb: the ctdb_connection from ctdb_connect. * * This returns POLLIN, possibly or'd with POLLOUT if there are writes * pending. You can set this straight into poll.events. * * See Also: * ctdb_service() */ int ctdb_which_events(struct ctdb_connection *ctdb); /** * ctdb_service - service any I/O and callbacks from ctdbd communication * @ctdb: the ctdb_connection from ctdb_connect. * @revents: which events are available. * * This is the core of the library: it read and writes to the ctdbd * socket. It may call callbacks registered with the various _send * functions. * * revents is a bitset: POLLIN and/or POLLOUT may be set to indicate * it is worth attempting to read/write the (nonblocking) * filedescriptor respectively. * * Note that the synchronous functions call this internally. * Returns false on catastrophic failure. */ bool ctdb_service(struct ctdb_connection *ctdb, int revents); /** * struct ctdb_request - handle for an outstanding request * * This opaque structure returned from various *_send functions gives * you a handle by which you can cancel a request. You can't do * anything else with it until the request is completed and it is * handed to your callback function. */ struct ctdb_request; /** * ctdb_request_free - free a completed request * * This frees a request: you should only call it once it has been * handed to your callback. For incomplete requests, see ctdb_cancel(). */ void ctdb_request_free(struct ctdb_request *req); /** * ctdb_callback_t - callback for completed requests. * * This would normally unpack the request using ctdb_*_recv(). You * must free the request using ctdb_request_free(). * * Note that due to macro magic, actual your callback can be typesafe: * instead of taking a void *, it can take a type which matches the * actual private parameter. */ typedef void (*ctdb_callback_t)(struct ctdb_connection *ctdb, struct ctdb_request *req, void *private_data); /** * struct ctdb_db - connection to a particular open TDB * * This represents a particular open database: you receive it from * ctdb_attachdb or ctdb_attachdb_recv to manipulate a database. * * You have to free the handle with ctdb_detachdb() when finished with it. */ struct ctdb_db; /** * ctdb_attachdb_send - open a clustered TDB * @ctdb: the ctdb_connection from ctdb_connect. * @name: the filename of the database (no /). * @persistent: whether the database is persistent across ctdbd's life * @tdb_flags: the flags to pass to tdb_open. * @callback: the callback when we're attached or failed (typesafe) * @cbdata: the argument to callback() * * This function connects to a TDB controlled by ctdbd. It can create * a new TDB if it does not exist, depending on tdb_flags. Returns * the pending request, or NULL on error. */ struct ctdb_request * ctdb_attachdb_send(struct ctdb_connection *ctdb, const char *name, bool persistent, uint32_t tdb_flags, ctdb_callback_t callback, void *cbdata); /** * ctdb_attachdb_recv - read an ctdb_attach reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * * This returns NULL if something went wrong, or otherwise the open database. */ struct ctdb_db *ctdb_attachdb_recv(struct ctdb_connection *ctdb, struct ctdb_request *req); /** * struct ctdb_lock - a record lock on a clustered TDB database * * This locks a subset of the database across the entire cluster; it * is the fundamental sychronization element for ctdb. You cannot have * more than one lock at once. * * You MUST NOT block during holding this lock and MUST release it * quickly by performing ctdb_release_lock(lock). * Do NOT make any system calls that may block while holding the lock. * * Try to release the lock as quickly as possible. */ struct ctdb_lock; /** * ctdb_rrl_callback_t - callback for ctdb_readrecordlock_async * * This is not the standard ctdb_callback_t, because there is often no * request required to access a database record (ie. if it is local already). * So the callback is handed the lock directly: it might be NULL if there * was an error obtaining the lock. * * See Also: * ctdb_readrecordlock_async(), ctdb_readrecordlock() */ typedef void (*ctdb_rrl_callback_t)(struct ctdb_db *ctdb_db, struct ctdb_lock *lock, TDB_DATA data, void *private_data); /** * ctdb_readrecordlock_async - read and lock a record * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv. * @key: the key of the record to lock. * @callback: the callback once the record is locked (typesafe). * @cbdata: the argument to callback() * * This returns true on success. Commonly, we can obtain the record * immediately and so the callback will be invoked. Otherwise a request * will be queued to ctdbd for the record. * * If failure is immediate, false is returned. Otherwise, the callback * may receive a NULL lock arg to indicate asynchronous failure. */ bool ctdb_readrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key, ctdb_rrl_callback_t callback, void *cbdata); /** * ctdb_readonlyrecordlock_async - read and lock a record for read-only access * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv. * @key: the key of the record to lock. * @callback: the callback once the record is locked (typesafe). * @cbdata: the argument to callback() * * This returns true on success. Commonly, we can obtain the record * immediately and so the callback will be invoked. Otherwise a request * will be queued to ctdbd for the record. * * If failure is immediate, false is returned. Otherwise, the callback * may receive a NULL lock arg to indicate asynchronous failure. */ bool ctdb_readonlyrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key, ctdb_rrl_callback_t callback, void *cbdata); /** * ctdb_writerecord - write a locked record in a TDB * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv. * @lock: the lock from ctdb_readrecordlock/ctdb_readrecordlock_recv * @data: the new data to place in the record. */ bool ctdb_writerecord(struct ctdb_db *ctdb_db, struct ctdb_lock *lock, TDB_DATA data); /** * ctdb_release_lock - release a record lock on a TDB * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv. * @lock: the lock from ctdb_readrecordlock/ctdb_readrecordlock_async */ void ctdb_release_lock(struct ctdb_db *ctdb_db, struct ctdb_lock *lock); /** * ctdb_traverse_callback_t - callback for ctdb_traverse_async. * return 0 - to continue traverse * return 1 - to abort the traverse * * See Also: * ctdb_traverse_async() */ #define TRAVERSE_STATUS_RECORD 0 #define TRAVERSE_STATUS_FINISHED 1 #define TRAVERSE_STATUS_ERROR 2 typedef int (*ctdb_traverse_callback_t)(struct ctdb_connection *ctdb, struct ctdb_db *ctdb_db, int status, TDB_DATA key, TDB_DATA data, void *private_data); /** * ctdb_traverse_async - traverse a database. * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv. * @callback: the callback once the record is locked (typesafe). * @cbdata: the argument to callback() * * This returns true on success. * when successfull, the callback will be invoked for each record * until the traversal is finished. * * status == * TRAVERSE_STATUS_RECORD key/data contains a record. * TRAVERSE_STATUS_FINISHED traverse is finished. key/data is undefined. * TRAVERSE_STATUS_ERROR an error occured during traverse. * key/data is undefined. * * If failure is immediate, false is returned. */ bool ctdb_traverse_async(struct ctdb_db *ctdb_db, ctdb_traverse_callback_t callback, void *cbdata); /** * ctdb_message_fn_t - messaging callback for ctdb messages * * ctdbd provides a simple messaging API; you can register for a particular * 64-bit id on which you want to send messages, and send to other ids. * * See Also: * ctdb_set_message_handler_send() */ typedef void (*ctdb_message_fn_t)(struct ctdb_connection *, uint64_t srvid, TDB_DATA data, void *); /** * ctdb_set_message_handler_send - register for messages to a srvid * @ctdb: the ctdb_connection from ctdb_connect. * @srvid: the 64 bit identifier for our messages. * @handler: the callback when we receive such a message (typesafe) * @handler_data: the argument to handler() * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * Note: our callback will always be called before handler. * * See Also: * ctdb_set_message_handler_recv(), ctdb_remove_message_handler_send() */ struct ctdb_request * ctdb_set_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid, ctdb_message_fn_t handler, void *handler_data, ctdb_callback_t callback, void *cbdata); /** * ctdb_set_message_handler_recv - read a set_message_handler result * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request * * If this returns true, the registered handler may be called from the next * ctdb_service(). If this returns false, the registration failed. */ bool ctdb_set_message_handler_recv(struct ctdb_connection *ctdb, struct ctdb_request *handle); /** * ctdb_remove_message_handler_send - unregister for messages to a srvid * @ctdb: the ctdb_connection from ctdb_connect. * @srvid: the 64 bit identifier for our messages. * @handler: the callback when we receive such a message (typesafe) * @handler_data: the argument to handler() * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * This undoes a successful ctdb_set_message_handler or * ctdb_set_message_handler_recv. */ struct ctdb_request * ctdb_remove_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid, ctdb_message_fn_t handler, void *handler_data, ctdb_callback_t callback, void *cbdata); /** * ctdb_remove_message_handler_recv - read a remove_message_handler result * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request * * After this returns true, the registered handler will no longer be called. * If this returns false, the de-registration failed. */ bool ctdb_remove_message_handler_recv(struct ctdb_connection *ctdb, struct ctdb_request *req); /** * ctdb_send_message - send a message via ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @pnn: the physical node number to send to * @srvid: the 64 bit identifier for this message type. * @data: the data to send * * This allows arbitrary messages to be sent across the cluster to those * listening (via ctdb_set_message_handler et al). * * This queues a message to be sent: you will need to call * ctdb_service() to actually send the message. There is no callback * because there is no acknowledgement. * * See Also: * ctdb_getpnn_send(), ctdb_getpnn() */ bool ctdb_send_message(struct ctdb_connection *ctdb, uint32_t pnn, uint64_t srvid, TDB_DATA data); /** * ctdb_getpnn_send - read the pnn number of a node. * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getpnn_send(struct ctdb_connection *ctdb, uint32_t destnode, ctdb_callback_t callback, void *cbdata); /** * ctdb_getpnn_recv - read an ctdb_getpnn reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @pnn: a pointer to the pnn to fill in * * This returns false if something went wrong, or otherwise fills in pnn. */ bool ctdb_getpnn_recv(struct ctdb_connection *ctdb, struct ctdb_request *req, uint32_t *pnn); /** * ctdb_getdbstat_send - read statistics for a db * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @db_id: the database to collect the statistics from * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getdbstat_send(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t db_id, ctdb_callback_t callback, void *cbdata); /** * ctdb_getdbstat_recv - read an ctdb_getdbstat reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @stat: a pointer to the *stat to fill in * * This returns false if something went wrong, or otherwise fills in **stats * stats must be freed later by calling ctdb_free_dbstat(); */ bool ctdb_getdbstat_recv(struct ctdb_connection *ctdb, struct ctdb_request *req, struct ctdb_db_statistics **stat); void ctdb_free_dbstat(struct ctdb_db_statistics *stat); /** * ctdb_check_message_handlers_send - check a list of message_handlers * if they are registered * message_handlers are registered on the daemon using the * ctdb_set_message_handler_send() call * * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @num: number of srvids to check * @mhs: @num message_handlers values to check * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_check_message_handlers_send(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t num, uint64_t *mhs, ctdb_callback_t callback, void *cbdata); /** * ctdb_check_message_handlers_recv - read a ctdb_check_message_handlers * reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @num: number of message_handlers to check * @result: an array of @num uint8_t fields containing the result of the check * 0: message_handler does not exist * 1: message_handler exists * * This returns false if something went wrong, or otherwise fills in result. */ bool ctdb_check_message_handlers_recv(struct ctdb_connection *ctdb, struct ctdb_request *req, uint32_t num, uint8_t *result); /** * ctdb_getcapabilities_send - read the capabilities of a node * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getcapabilities_send(struct ctdb_connection *ctdb, uint32_t destnode, ctdb_callback_t callback, void *cbdata); /** * ctdb_getcapabilities_recv - read an ctdb_getcapabilities reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @capabilities: a pointer to the capabilities to fill in * * This returns false if something went wrong, or otherwise fills in * capabilities. */ bool ctdb_getcapabilities_recv(struct ctdb_connection *ctdb, struct ctdb_request *handle, uint32_t *capabilities); /** * ctdb_getdbseqnum_send - read the sequence number off a db * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @dbid: database id * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getdbseqnum_send(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t dbid, ctdb_callback_t callback, void *cbdata); /** * ctdb_getdbseqnum_recv - read the sequence number off a database * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @seqnum: a pointer to the seqnum to fill in * * This returns false if something went wrong, or otherwise fills in pnn. */ bool ctdb_getdbseqnum_recv(struct ctdb_connection *ctdb, struct ctdb_request *req, uint64_t *seqnum); /** * ctdb_getnodemap_send - read the nodemap number from a node. * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getnodemap_send(struct ctdb_connection *ctdb, uint32_t destnode, ctdb_callback_t callback, void *cbdata); /** * ctdb_getnodemap_recv - read an ctdb_getnodemap reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @nodemap: a pointer to the returned nodemap structure * * This returns false if something went wrong. * If the command failed, it guarantees to set nodemap to NULL. * A non-NULL value for nodemap means the command was successful. * * A non-NULL value of the nodemap must be release released/freed * by ctdb_free_nodemap(). */ bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb, struct ctdb_request *req, struct ctdb_node_map **nodemap); /** * ctdb_getifaces_send - read the list of interfaces from a node. * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getifaces_send(struct ctdb_connection *ctdb, uint32_t destnode, ctdb_callback_t callback, void *cbdata); /** * ctdb_getifaces_recv - read an ctdb_getifaces reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @ifaces: the list of interfaces * * This returns false if something went wrong. * If the command failed, it guarantees to set ifaces to NULL. * A non-NULL value for ifaces means the command was successful. * * A non-NULL value of the ifaces must be release released/freed * by ctdb_free_ifaces(). */ bool ctdb_getifaces_recv(struct ctdb_connection *ctdb, struct ctdb_request *req, struct ctdb_ifaces_list **ifaces); /* Free a datastructure returned by ctdb_getifaces[_recv] */ void ctdb_free_ifaces(struct ctdb_ifaces_list *ifaces); /** * ctdb_getpublicips_send - read the public ip list from a node. * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * This control returns the list of public ips known to the local node. * Deamons only know about those ips that are listed in the local * public addresses file, which means the returned list of ips may * be only a subset of all ips across the entire cluster. * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getpublicips_send(struct ctdb_connection *ctdb, uint32_t destnode, ctdb_callback_t callback, void *cbdata); /** * ctdb_getpublicips_recv - read the public ip list from a node * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @ips: a pointer to the returned public ip list * * This returns false if something went wrong. * If the command failed, it guarantees to set ips to NULL. * A non-NULL value for nodemap means the command was successful. * * A non-NULL value of the nodemap must be release released/freed * by ctdb_free_publicips(). */ bool ctdb_getpublicips_recv(struct ctdb_connection *ctdb, struct ctdb_request *req, struct ctdb_all_public_ips **ips); /** * ctdb_getrecmaster_send - read the recovery master of a node * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getrecmaster_send(struct ctdb_connection *ctdb, uint32_t destnode, ctdb_callback_t callback, void *cbdata); /** * ctdb_getrecmaster_recv - read an ctdb_getrecmaster reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @recmaster: a pointer to the recmaster to fill in * * This returns false if something went wrong, or otherwise fills in * recmaster. */ bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb, struct ctdb_request *handle, uint32_t *recmaster); /** * ctdb_getrecmode_send - read the recovery mode of a node * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getrecmode_send(struct ctdb_connection *ctdb, uint32_t destnode, ctdb_callback_t callback, void *cbdata); /** * ctdb_getrecmode_recv - read an ctdb_getrecmode reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @recmode: a pointer to the recmode to fill in * * This returns false if something went wrong, or otherwise fills in * recmode. */ bool ctdb_getrecmode_recv(struct ctdb_connection *ctdb, struct ctdb_request *handle, uint32_t *recmode); /** * ctdb_getvnnmap_send - read the vnn map from a node. * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @callback: the callback when ctdb replies to our message (typesafe) * @cbdata: the argument to callback() * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ struct ctdb_request * ctdb_getvnnmap_send(struct ctdb_connection *ctdb, uint32_t destnode, ctdb_callback_t callback, void *cbdata); /** * ctdb_getvnnmap_recv - read an ctdb_getvnnmap reply from ctdbd * @ctdb: the ctdb_connection from ctdb_connect. * @req: the completed request. * @vnnmap: the list of interfaces * * This returns false if something went wrong. * If the command failed, it guarantees to set vnnmap to NULL. * A non-NULL value for vnnmap means the command was successful. * * A non-NULL value of the vnnmap must be released/freed * by ctdb_free_vnnmap(). */ bool ctdb_getvnnmap_recv(struct ctdb_connection *ctdb, struct ctdb_request *req, struct ctdb_vnn_map **vnnmap); /** * ctdb_cancel - cancel an uncompleted request * @ctdb: the ctdb_connection from ctdb_connect. * @req: the uncompleted request. * * This cancels a request, returning true. You may not cancel a * request which has already been completed (ie. once its callback has * been called); you should simply use ctdb_request_free() in that case. */ void ctdb_cancel(struct ctdb_connection *ctdb, struct ctdb_request *req); /*** * * Synchronous API * ***/ /** * ctdb_attachdb - open a clustered TDB (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @name: the filename of the database (no /). * @persistent: whether the database is persistent across ctdbd's life * @tdb_flags: the flags to pass to tdb_open. * * Do a ctdb_attachdb_send and wait for it to complete. * Returns NULL on failure. */ struct ctdb_db *ctdb_attachdb(struct ctdb_connection *ctdb, const char *name, bool persistent, uint32_t tdb_flags); /** * ctdb_detachdb - close a clustered TDB. * @ctdb: the ctdb_connection from ctdb_connect. * @db: the database from ctdb_attachdb/ctdb_attachdb_send * * Closes a clustered tdb. */ void ctdb_detachdb(struct ctdb_connection *ctdb, struct ctdb_db *db); /** * ctdb_readrecordlock - read and lock a record (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @ctdb_db: the database handle from ctdb_attachdb/ctdb_attachdb_recv. * @key: the key of the record to lock. * @req: a pointer to the request, if one is needed. * * Do a ctdb_readrecordlock_send and wait for it to complete. * Returns NULL on failure. */ struct ctdb_lock *ctdb_readrecordlock(struct ctdb_connection *ctdb, struct ctdb_db *ctdb_db, TDB_DATA key, TDB_DATA *data); /** * ctdb_set_message_handler - register for messages to a srvid (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @srvid: the 64 bit identifier for our messages. * @handler: the callback when we receive such a message (typesafe) * @cbdata: the argument to handler() * * If this returns true, the message handler can be called from any * ctdb_service() (which is also called indirectly by other * synchronous functions). If this returns false, the registration * failed. */ bool ctdb_set_message_handler(struct ctdb_connection *ctdb, uint64_t srvid, ctdb_message_fn_t handler, void *cbdata); /** * ctdb_remove_message_handler - deregister for messages (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @srvid: the 64 bit identifier for our messages. * @handler: the callback when we receive such a message (typesafe) * @handler_data: the argument to handler() * * If this returns true, the message handler will no longer be called. * If this returns false, the deregistration failed. */ bool ctdb_remove_message_handler(struct ctdb_connection *ctdb, uint64_t srvid, ctdb_message_fn_t handler, void *handler_data); /** * ctdb_getpnn - read the pnn number of a node (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @pnn: a pointer to the pnn to fill in * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * Returns true and fills in *pnn on success. */ bool ctdb_getpnn(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t *pnn); /** * ctdb_getdbstat - read the db stat of a node (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @db_id: the database to collect the statistics from * @stat: a pointer to the *stat to fill in * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * This returns false if something went wrong, or otherwise fills in **stat * stat must be freed later by calling ctdb_free_dbstat(); */ bool ctdb_getdbstat(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t db_id, struct ctdb_db_statistics **stat); /** * ctdb_check_message_handlers - check a list of message_handlers (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @num: number of srvids to check * @mhs: @num message_handlers to check * @result: an array of @num uint8_t fields containing the result of the check * 0: message_handler does not exist * 1: message_handler exists * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. */ bool ctdb_check_message_handlers(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t num, uint64_t *mhs, uint8_t *result); /** * ctdb_getcapabilities - read the capabilities of a node (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @capabilities: a pointer to the capabilities to fill in * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * Returns true and fills in *capabilities on success. */ bool ctdb_getcapabilities(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t *capabilities); /** * ctdb_getdbseqnum - read the seqnum of a database * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @dbid: database id * @seqnum: sequence number for the database * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * Returns true and fills in *pnn on success. */ bool ctdb_getdbseqnum(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t dbid, uint64_t *seqnum); /** * ctdb_getrecmaster - read the recovery master of a node (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @recmaster: a pointer to the recmaster to fill in * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * Returns true and fills in *recmaster on success. */ bool ctdb_getrecmaster(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t *recmaster); /** * ctdb_getrecmode - read the recovery mode of a node (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @recmode: a pointer to the recmode to fill in * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * Returns true and fills in *recmode on success. */ bool ctdb_getrecmode(struct ctdb_connection *ctdb, uint32_t destnode, uint32_t *recmode); /** * ctdb_getnodemap - read the nodemap from a node (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @nodemap: a pointer to the nodemap to fill in * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * Returns true and fills in *nodemap on success. * A non-NULL nodemap must be freed by calling ctdb_free_nodemap. */ bool ctdb_getnodemap(struct ctdb_connection *ctdb, uint32_t destnode, struct ctdb_node_map **nodemap); /** * ctdb_getifaces - read the list of interfaces from a node (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @ifaces: a pointer to the ifaces to fill in * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * Returns true and fills in *ifaces on success. * A non-NULL value of the ifaces must be release released/freed * by ctdb_free_ifaces(). */ bool ctdb_getifaces(struct ctdb_connection *ctdb, uint32_t destnode, struct ctdb_ifaces_list **ifaces); /* * This function is used to release/free the nodemap structure returned * by ctdb_getnodemap() and ctdb_getnodemap_recv() */ void ctdb_free_nodemap(struct ctdb_node_map *nodemap); /** * ctdb_getpublicips - read the public ip list from a node. * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @ips: a pointer to the returned public ip list * * This control returns the list of public ips known to the local node. * Deamons only know about those ips that are listed in the local * public addresses file, which means the returned list of ips may * be only a subset of all ips across the entire cluster. * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * This returns false if something went wrong. * If the command failed, it guarantees to set ips to NULL. * A non-NULL value for nodemap means the command was successful. * * A non-NULL value of the nodemap must be release released/freed * by ctdb_free_publicips(). */ bool ctdb_getpublicips(struct ctdb_connection *ctdb, uint32_t destnode, struct ctdb_all_public_ips **ips); /* * This function is used to release/free the public ip structure returned * by ctdb_getpublicips() and ctdb_getpublicips_recv() */ void ctdb_free_publicips(struct ctdb_all_public_ips *ips); /** * ctdb_getvnnmap - read the vnn map from a node (synchronous) * @ctdb: the ctdb_connection from ctdb_connect. * @destnode: the destination node (see below) * @vnnmap: a pointer to the vnnmap to fill in * * There are several special values for destnode, detailed in * ctdb_protocol.h, particularly CTDB_CURRENT_NODE which means the * local ctdbd. * * Returns true and fills in *vnnmap on success. * A non-NULL value of the vnnmap must be released/freed * by ctdb_free_vnnmap(). */ bool ctdb_getvnnmap(struct ctdb_connection *ctdb, uint32_t destnode, struct ctdb_vnn_map **vnnmap); /* * This function is used to release/free the vnnmap structure returned * by ctdb_getvnnmap() and ctdb_getvnnmap_recv() */ void ctdb_free_vnnmap(struct ctdb_vnn_map *vnnmap); /* These ugly macro wrappers make the callbacks typesafe. */ #include #define ctdb_sendcb(cb, cbdata) \ typesafe_cb_preargs(void, (cb), (cbdata), \ struct ctdb_connection *, struct ctdb_request *) #define ctdb_msgcb(cb, cbdata) \ typesafe_cb_preargs(void, (cb), (cbdata), \ struct ctdb_connection *, uint64_t, TDB_DATA) #define ctdb_connect(addr, log, logpriv) \ ctdb_connect((addr), \ typesafe_cb_postargs(void, (log), (logpriv), \ int, const char *, va_list), \ (logpriv)) #define ctdb_set_message_handler(ctdb, srvid, handler, hdata) \ ctdb_set_message_handler((ctdb), (srvid), \ ctdb_msgcb((handler), (hdata)), (hdata)) #define ctdb_remove_message_handler(ctdb, srvid, handler, hdata) \ ctdb_remove_message_handler((ctdb), (srvid), \ ctdb_msgcb((handler), (hdata)), (hdata)) #define ctdb_attachdb_send(ctdb, name, persistent, tdb_flags, cb, cbdata) \ ctdb_attachdb_send((ctdb), (name), (persistent), (tdb_flags), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_readrecordlock_async(_ctdb_db, key, cb, cbdata) \ ctdb_readrecordlock_async((_ctdb_db), (key), \ typesafe_cb_preargs(void, (cb), (cbdata), \ struct ctdb_db *, struct ctdb_lock *, \ TDB_DATA), (cbdata)) #define ctdb_set_message_handler_send(ctdb, srvid, handler, hdata, cb, cbdata) \ ctdb_set_message_handler_send((ctdb), (srvid), \ ctdb_msgcb((handler), (hdata)), (hdata), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_remove_message_handler_send(ctdb, srvid, handler, hdata, cb, cbdata) \ ctdb_remove_message_handler_send((ctdb), (srvid), \ ctdb_msgcb((handler), (hdata)), (hdata), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getpnn_send(ctdb, destnode, cb, cbdata) \ ctdb_getpnn_send((ctdb), (destnode), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getcapabilities_send(ctdb, destnode, cb, cbdata) \ ctdb_getcapabilities_send((ctdb), (destnode), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getdbstat_send(ctdb, destnode, db_id, cb, cbdata) \ ctdb_getdbstat_send((ctdb), (destnode), (db_id), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_check_message_handlers_send(ctdb, destnode, num, mhs, \ cb, cbdata) \ ctdb_check_message_handlers_send((ctdb), (destnode), (num), \ (mhs), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getrecmaster_send(ctdb, destnode, cb, cbdata) \ ctdb_getrecmaster_send((ctdb), (destnode), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getrecmode_send(ctdb, destnode, cb, cbdata) \ ctdb_getrecmode_send((ctdb), (destnode), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getnodemap_send(ctdb, destnode, cb, cbdata) \ ctdb_getnodemap_send((ctdb), (destnode), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getpublicips_send(ctdb, destnode, cb, cbdata) \ ctdb_getpublicips_send((ctdb), (destnode), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getdbseqnum_send(ctdb, destnode, dbid, cb, cbdata) \ ctdb_getdbseqnum_send((ctdb), (destnode), (dbid), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getifaces_send(ctdb, destnode, cb, cbdata) \ ctdb_getifaces_send((ctdb), (destnode), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #define ctdb_getvnnmap_send(ctdb, destnode, cb, cbdata) \ ctdb_getvnnmap_send((ctdb), (destnode), \ ctdb_sendcb((cb), (cbdata)), (cbdata)) #endif ctdb-2.5.1.dfsg/include/includes.h0000644000175000017500000000413312245023514016630 0ustar mathieumathieu#ifndef _CTDB_INCLUDES_H #define _CTDB_INCLUDES_H #define HAVE_UNIXSOCKET 1 #include "replace.h" #include "talloc.h" #include "system/wait.h" #include "system/network.h" #include "tdb.h" #include "idtree.h" #include "ctdb_client.h" /* Allow use of deprecated function tevent_loop_allow_nesting() */ #define TEVENT_DEPRECATED /* Saves ctdb from massive churn. */ #define TEVENT_COMPAT_DEFINES 1 #include "tevent.h" extern int LogLevel; extern int this_log_level; enum debug_level { DEBUG_EMERG = -3, DEBUG_ALERT = -2, DEBUG_CRIT = -1, DEBUG_ERR = 0, DEBUG_WARNING = 1, DEBUG_NOTICE = 2, DEBUG_INFO = 3, DEBUG_DEBUG = 4, }; #define DEBUGLVL(lvl) ((lvl) <= LogLevel) #define DEBUG(lvl, x) do { this_log_level = (lvl); if ((lvl) < DEBUG_DEBUG) { log_ringbuffer x; } if ((lvl) <= LogLevel) { do_debug x; }} while (0) #define DEBUGADD(lvl, x) do { if ((lvl) <= LogLevel) { this_log_level = (lvl); do_debug_add x; }} while (0) #define _PUBLIC_ #define _NORETURN_ #define _PURE_ #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) #endif struct timeval timeval_zero(void); bool timeval_is_zero(const struct timeval *tv); struct timeval timeval_current(void); struct timeval timeval_set(uint32_t secs, uint32_t usecs); int timeval_compare(const struct timeval *tv1, const struct timeval *tv2); struct timeval timeval_until(const struct timeval *tv1, const struct timeval *tv2); _PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs); double timeval_elapsed(struct timeval *tv); double timeval_delta(struct timeval *tv2, struct timeval *tv); char **file_lines_load(const char *fname, int *numlines, TALLOC_CTX *mem_ctx); char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len); uint8_t *hex_decode_talloc(TALLOC_CTX *mem_ctx, const char *hex_in, size_t *len); _PUBLIC_ const char **str_list_add(const char **list, const char *s); _PUBLIC_ int set_blocking(int fd, bool set); #include "lib/util/debug.h" #include "lib/util/util.h" #endif /* _CTDB_INCLUDES_H */ ctdb-2.5.1.dfsg/include/ctdb_private.h0000644000175000017500000015272712245023514017505 0ustar mathieumathieu/* ctdb database library Copyright (C) Andrew Tridgell 2006 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #ifndef _CTDB_PRIVATE_H #define _CTDB_PRIVATE_H #include "ctdb_client.h" #include /* * Structures to support SRVID requests and replies */ struct srvid_request { uint32_t pnn; uint64_t srvid; }; struct srvid_request_data { uint32_t pnn; uint64_t srvid; uint32_t data; }; /* * pid of the ctdbd daemon */ extern pid_t ctdbd_pid; /* a tcp connection description also used by tcp_add and tcp_remove controls */ struct ctdb_tcp_connection { ctdb_sock_addr src_addr; ctdb_sock_addr dst_addr; }; /* the wire representation for a tcp tickle array */ struct ctdb_tcp_wire_array { uint32_t num; struct ctdb_tcp_connection connections[1]; }; /* the list of tcp tickles used by get/set tcp tickle list */ struct ctdb_control_tcp_tickle_list { ctdb_sock_addr addr; struct ctdb_tcp_wire_array tickles; }; /* array of tcp connections */ struct ctdb_tcp_array { uint32_t num; struct ctdb_tcp_connection *connections; }; /* all tunable variables go in here */ struct ctdb_tunable { uint32_t max_redirect_count; uint32_t seqnum_interval; /* unit is ms */ uint32_t control_timeout; uint32_t traverse_timeout; uint32_t keepalive_interval; uint32_t keepalive_limit; uint32_t recover_timeout; uint32_t recover_interval; uint32_t election_timeout; uint32_t takeover_timeout; uint32_t monitor_interval; uint32_t tickle_update_interval; uint32_t script_timeout; uint32_t script_timeout_count; /* allow dodgy scripts to hang this many times in a row before we mark the node unhealthy */ uint32_t script_unhealthy_on_timeout; /* obsolete */ uint32_t recovery_grace_period; uint32_t recovery_ban_period; uint32_t database_hash_size; uint32_t database_max_dead; uint32_t rerecovery_timeout; uint32_t enable_bans; uint32_t deterministic_public_ips; uint32_t reclock_ping_period; uint32_t no_ip_failback; uint32_t disable_ip_failover; uint32_t verbose_memory_names; uint32_t recd_ping_timeout; uint32_t recd_ping_failcount; uint32_t log_latency_ms; uint32_t reclock_latency_ms; uint32_t recovery_drop_all_ips; uint32_t verify_recovery_lock; uint32_t vacuum_interval; uint32_t vacuum_max_run_time; uint32_t repack_limit; uint32_t vacuum_limit; uint32_t max_queue_depth_drop_msg; uint32_t use_status_events_for_monitoring; uint32_t allow_unhealthy_db_read; uint32_t stat_history_interval; uint32_t deferred_attach_timeout; uint32_t vacuum_fast_path_count; uint32_t lcp2_public_ip_assignment; uint32_t allow_client_db_attach; uint32_t recover_pdb_by_seqnum; uint32_t deferred_rebalance_on_node_add; uint32_t fetch_collapse; uint32_t hopcount_make_sticky; uint32_t sticky_duration; uint32_t sticky_pindown; uint32_t no_ip_takeover; uint32_t db_record_count_warn; uint32_t db_record_size_warn; uint32_t db_size_warn; uint32_t pulldb_preallocation_size; uint32_t no_ip_host_on_all_disabled; uint32_t samba3_hack; }; /* an installed ctdb remote call */ struct ctdb_registered_call { struct ctdb_registered_call *next, *prev; uint32_t id; ctdb_fn_t fn; }; /* this address structure might need to be generalised later for some transports */ struct ctdb_address { const char *address; int port; }; /* check that a pnn is valid */ #define ctdb_validate_pnn(ctdb, pnn) (((uint32_t)(pnn)) < (ctdb)->num_nodes) /* called from the queue code when a packet comes in. Called with data==NULL on error */ typedef void (*ctdb_queue_cb_fn_t)(uint8_t *data, size_t length, void *private_data); /* used for callbacks in ctdb_control requests */ typedef void (*ctdb_control_callback_fn_t)(struct ctdb_context *, int32_t status, TDB_DATA data, const char *errormsg, void *private_data); /* structure describing a connected client in the daemon */ struct ctdb_client { struct ctdb_context *ctdb; int fd; struct ctdb_queue *queue; uint32_t client_id; pid_t pid; struct ctdb_tcp_list *tcp_list; uint32_t db_id; uint32_t num_persistent_updates; struct ctdb_client_notify_list *notify; }; struct ctdb_iface; /* state associated with a public ip address */ struct ctdb_vnn { struct ctdb_vnn *prev, *next; struct ctdb_iface *iface; const char **ifaces; ctdb_sock_addr public_address; uint8_t public_netmask_bits; /* the node number that is serving this public address, if any. If no node serves this ip it is set to -1 */ int32_t pnn; /* List of clients to tickle for this public address */ struct ctdb_tcp_array *tcp_array; /* whether we need to update the other nodes with changes to our list of connected clients */ bool tcp_update_needed; /* a context to hang sending gratious arp events off */ TALLOC_CTX *takeover_ctx; struct ctdb_kill_tcp *killtcp; /* Set to true any time an update to this VNN is in flight. This helps to avoid races. */ bool update_in_flight; }; /* state associated with one node */ struct ctdb_node { struct ctdb_context *ctdb; struct ctdb_address address; const char *name; /* for debug messages */ void *private_data; /* private to transport */ uint32_t pnn; uint32_t flags; /* used by the dead node monitoring */ uint32_t dead_count; uint32_t rx_cnt; uint32_t tx_cnt; /* used to track node capabilities, is only valid/tracked inside the recovery daemon. */ uint32_t capabilities; /* a list of controls pending to this node, so we can time them out quickly if the node becomes disconnected */ struct daemon_control_state *pending_controls; /* used by the recovery daemon when distributing ip addresses across the nodes. it needs to know which public ip's can be handled by each node. */ struct ctdb_all_public_ips *known_public_ips; struct ctdb_all_public_ips *available_public_ips; /* used by the recovery dameon to track when a node should be banned */ struct ctdb_banning_state *ban_state; }; /* transport specific methods */ struct ctdb_methods { int (*initialise)(struct ctdb_context *); /* initialise transport structures */ int (*start)(struct ctdb_context *); /* start the transport */ int (*add_node)(struct ctdb_node *); /* setup a new node */ int (*connect_node)(struct ctdb_node *); /* connect to node */ int (*queue_pkt)(struct ctdb_node *, uint8_t *data, uint32_t length); void *(*allocate_pkt)(TALLOC_CTX *mem_ctx, size_t ); void (*shutdown)(struct ctdb_context *); /* shutdown transport */ void (*restart)(struct ctdb_node *); /* stop and restart the connection */ }; /* transport calls up to the ctdb layer */ struct ctdb_upcalls { /* recv_pkt is called when a packet comes in */ void (*recv_pkt)(struct ctdb_context *, uint8_t *data, uint32_t length); /* node_dead is called when an attempt to send to a node fails */ void (*node_dead)(struct ctdb_node *); /* node_connected is called when a connection to a node is established */ void (*node_connected)(struct ctdb_node *); }; /* list of message handlers - needs to be changed to a more efficient data structure so we can find a message handler given a srvid quickly */ struct ctdb_message_list_header { struct ctdb_message_list_header *next, *prev; struct ctdb_context *ctdb; uint64_t srvid; struct ctdb_message_list *m; }; struct ctdb_message_list { struct ctdb_message_list *next, *prev; struct ctdb_message_list_header *h; ctdb_msg_fn_t message_handler; void *message_private; }; /* additional data required for the daemon mode */ struct ctdb_daemon_data { int sd; char *name; struct ctdb_queue *queue; }; #define CTDB_UPDATE_STAT(ctdb, counter, value) \ { \ if (value > ctdb->statistics.counter) { \ ctdb->statistics.counter = c->hopcount; \ } \ if (value > ctdb->statistics_current.counter) { \ ctdb->statistics_current.counter = c->hopcount; \ } \ } #define CTDB_INCREMENT_STAT(ctdb, counter) \ { \ ctdb->statistics.counter++; \ ctdb->statistics_current.counter++; \ } #define CTDB_DECREMENT_STAT(ctdb, counter) \ { \ if (ctdb->statistics.counter > 0) \ ctdb->statistics.counter--; \ if (ctdb->statistics_current.counter > 0) \ ctdb->statistics_current.counter--; \ } #define CTDB_INCREMENT_DB_STAT(ctdb_db, counter) \ { \ ctdb_db->statistics.counter++; \ } #define CTDB_DECREMENT_DB_STAT(ctdb_db, counter) \ { \ if (ctdb_db->statistics.counter > 0) \ ctdb_db->statistics.counter--; \ } #define CTDB_UPDATE_RECLOCK_LATENCY(ctdb, name, counter, value) \ { \ if (value > ctdb->statistics.counter.max) \ ctdb->statistics.counter.max = value; \ if (value > ctdb->statistics_current.counter.max) \ ctdb->statistics_current.counter.max = value; \ \ if (ctdb->statistics.counter.num == 0 || \ value < ctdb->statistics.counter.min) \ ctdb->statistics.counter.min = value; \ if (ctdb->statistics_current.counter.num == 0 || \ value < ctdb->statistics_current.counter.min) \ ctdb->statistics_current.counter.min = value; \ \ ctdb->statistics.counter.total += value; \ ctdb->statistics_current.counter.total += value; \ \ ctdb->statistics.counter.num++; \ ctdb->statistics_current.counter.num++; \ \ if (ctdb->tunable.reclock_latency_ms != 0) { \ if (value*1000 > ctdb->tunable.reclock_latency_ms) { \ DEBUG(DEBUG_ERR, \ ("High RECLOCK latency %fs for operation %s\n", \ value, name)); \ } \ } \ } #define CTDB_UPDATE_DB_LATENCY(ctdb_db, operation, counter, value) \ { \ if (value > ctdb_db->statistics.counter.max) \ ctdb_db->statistics.counter.max = value; \ if (ctdb_db->statistics.counter.num == 0 || \ value < ctdb_db->statistics.counter.min) \ ctdb_db->statistics.counter.min = value; \ \ ctdb_db->statistics.counter.total += value; \ ctdb_db->statistics.counter.num++; \ \ if (ctdb_db->ctdb->tunable.log_latency_ms != 0) { \ if (value*1000 > ctdb_db->ctdb->tunable.log_latency_ms) { \ DEBUG(DEBUG_ERR, \ ("High latency %.6fs for operation %s on database %s\n",\ value, operation, ctdb_db->db_name)); \ } \ } \ } #define CTDB_UPDATE_LATENCY(ctdb, db, operation, counter, t) \ { \ double l = timeval_elapsed(&t); \ \ if (l > ctdb->statistics.counter.max) \ ctdb->statistics.counter.max = l; \ if (l > ctdb->statistics_current.counter.max) \ ctdb->statistics_current.counter.max = l; \ \ if (ctdb->statistics.counter.num == 0 || \ l < ctdb->statistics.counter.min) \ ctdb->statistics.counter.min = l; \ if (ctdb->statistics_current.counter.num == 0 || \ l < ctdb->statistics_current.counter.min) \ ctdb->statistics_current.counter.min = l; \ \ ctdb->statistics.counter.total += l; \ ctdb->statistics_current.counter.total += l; \ \ ctdb->statistics.counter.num++; \ ctdb->statistics_current.counter.num++; \ \ if (ctdb->tunable.log_latency_ms != 0) { \ if (l*1000 > ctdb->tunable.log_latency_ms) { \ DEBUG(DEBUG_WARNING, \ ("High latency %.6fs for operation %s on database %s\n",\ l, operation, db->db_name)); \ } \ } \ } /* a structure that contains the elements required for the write record control */ struct ctdb_write_record { uint32_t dbid; uint32_t keylen; uint32_t datalen; unsigned char blob[1]; }; enum ctdb_freeze_mode {CTDB_FREEZE_NONE, CTDB_FREEZE_PENDING, CTDB_FREEZE_FROZEN}; enum ctdb_runstate { CTDB_RUNSTATE_UNKNOWN, CTDB_RUNSTATE_INIT, CTDB_RUNSTATE_SETUP, CTDB_RUNSTATE_FIRST_RECOVERY, CTDB_RUNSTATE_STARTUP, CTDB_RUNSTATE_RUNNING, CTDB_RUNSTATE_SHUTDOWN, }; const char *runstate_to_string(enum ctdb_runstate runstate); enum ctdb_runstate runstate_from_string(const char *label); void ctdb_set_runstate(struct ctdb_context *ctdb, enum ctdb_runstate runstate); void ctdb_shutdown_sequence(struct ctdb_context *ctdb, int exit_code); #define CTDB_MONITORING_ACTIVE 0 #define CTDB_MONITORING_DISABLED 1 #define NUM_DB_PRIORITIES 3 /* main state of the ctdb daemon */ struct ctdb_context { struct tevent_context *ev; struct timeval ctdbd_start_time; struct timeval last_recovery_started; struct timeval last_recovery_finished; uint32_t recovery_mode; TALLOC_CTX *tickle_update_context; TALLOC_CTX *keepalive_ctx; TALLOC_CTX *check_public_ifaces_ctx; struct ctdb_tunable tunable; enum ctdb_freeze_mode freeze_mode[NUM_DB_PRIORITIES+1]; struct ctdb_freeze_handle *freeze_handles[NUM_DB_PRIORITIES+1]; bool freeze_transaction_started; uint32_t freeze_transaction_id; struct ctdb_address address; const char *name; const char *db_directory; const char *db_directory_persistent; const char *db_directory_state; struct tdb_wrap *db_persistent_health; uint32_t db_persistent_startup_generation; uint64_t db_persistent_check_errors; uint64_t max_persistent_check_errors; const char *transport; char *recovery_lock_file; int recovery_lock_fd; uint32_t pnn; /* our own pnn */ uint32_t num_nodes; uint32_t num_connected; unsigned flags; uint32_t capabilities; struct idr_context *idr; int lastid; struct ctdb_node **nodes; /* array of nodes in the cluster - indexed by vnn */ struct ctdb_vnn *vnn; /* list of public ip addresses and interfaces */ struct ctdb_vnn *single_ip_vnn; /* a structure for the single ip */ struct ctdb_iface *ifaces; /* list of local interfaces */ char *err_msg; const struct ctdb_methods *methods; /* transport methods */ const struct ctdb_upcalls *upcalls; /* transport upcalls */ void *private_data; /* private to transport */ struct ctdb_db_context *db_list; struct ctdb_message_list_header *message_list_header; struct tdb_context *message_list_indexdb; struct ctdb_daemon_data daemon; struct ctdb_statistics statistics; struct ctdb_statistics statistics_current; #define MAX_STAT_HISTORY 100 struct ctdb_statistics statistics_history[MAX_STAT_HISTORY]; struct ctdb_vnn_map *vnn_map; uint32_t num_clients; uint32_t recovery_master; struct ctdb_call_state *pending_calls; struct ctdb_client_ip *client_ip_list; bool do_checkpublicip; struct trbt_tree *server_ids; bool do_setsched; void *saved_scheduler_param; const char *event_script_dir; const char *notification_script; const char *default_public_interface; pid_t ctdbd_pid; pid_t recoverd_pid; pid_t syslogd_pid; enum ctdb_runstate runstate; struct ctdb_monitor_state *monitor; struct ctdb_log_state *log; int start_as_disabled; int start_as_stopped; bool valgrinding; uint32_t event_script_timeouts; /* counting how many consecutive times an eventscript has timedout */ uint32_t *recd_ping_count; TALLOC_CTX *recd_ctx; /* a context used to track recoverd monitoring events */ TALLOC_CTX *release_ips_ctx; /* a context used to automatically drop all IPs if we fail to recover the node */ TALLOC_CTX *event_script_ctx; struct ctdb_event_script_state *current_monitor; struct ctdb_scripts_wire *last_status[CTDB_EVENT_MAX]; TALLOC_CTX *banning_ctx; struct ctdb_vacuum_child_context *vacuumers; /* mapping from pid to ctdb_client * */ struct ctdb_client_pid_list *client_pids; /* used in the recovery daemon to remember the ip allocation */ struct trbt_tree *ip_tree; /* Used to defer db attach requests while in recovery mode */ struct ctdb_deferred_attach_context *deferred_attach; /* if we are a child process, do we have a domain socket to send controls on */ bool can_send_controls; /* list of event script callback functions that are active */ struct event_script_callback *script_callbacks; struct ctdb_reloadips_handle *reload_ips; const char *nodes_file; const char *public_addresses_file; struct trbt_tree *child_processes; /* Used for locking record/db/alldb */ int lock_num_pending; struct lock_context *lock_current; struct lock_context *lock_pending; }; struct ctdb_db_context { struct ctdb_db_context *next, *prev; struct ctdb_context *ctdb; uint32_t db_id; uint32_t priority; bool persistent; bool readonly; /* Do we support read-only delegations ? */ bool sticky; /* Do we support sticky records ? */ const char *db_name; const char *db_path; struct tdb_wrap *ltdb; struct tdb_context *rottdb; /* ReadOnly tracking TDB */ struct ctdb_registered_call *calls; /* list of registered calls */ uint32_t seqnum; struct timed_event *seqnum_update; struct ctdb_traverse_local_handle *traverse; struct ctdb_vacuum_handle *vacuum_handle; char *unhealthy_reason; int pending_requests; struct revokechild_handle *revokechild_active; struct ctdb_persistent_state *persistent_state; struct trbt_tree *delete_queue; struct trbt_tree *sticky_records; int (*ctdb_ltdb_store_fn)(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data); /* used to track which records we are currently fetching so we can avoid sending duplicate fetch requests */ struct trbt_tree *deferred_fetch; struct ctdb_db_statistics statistics; int lock_num_current; }; #define CTDB_NO_MEMORY(ctdb, p) do { if (!(p)) { \ DEBUG(0,("Out of memory for %s at %s\n", #p, __location__)); \ ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \ return -1; }} while (0) #define CTDB_NO_MEMORY_VOID(ctdb, p) do { if (!(p)) { \ DEBUG(0,("Out of memory for %s at %s\n", #p, __location__)); \ ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \ return; }} while (0) #define CTDB_NO_MEMORY_NULL(ctdb, p) do { if (!(p)) { \ DEBUG(0,("Out of memory for %s at %s\n", #p, __location__)); \ ctdb_set_error(ctdb, "Out of memory at %s:%d", __FILE__, __LINE__); \ return NULL; }} while (0) #define CTDB_NO_MEMORY_FATAL(ctdb, p) do { if (!(p)) { \ DEBUG(0,("Out of memory for %s at %s\n", #p, __location__)); \ ctdb_fatal(ctdb, "Out of memory in " __location__ ); \ }} while (0) /* structure passed in set_call control */ struct ctdb_control_set_call { uint32_t db_id; ctdb_fn_t fn; uint32_t id; }; /* struct for kill_tcp control */ struct ctdb_control_killtcp { ctdb_sock_addr src_addr; ctdb_sock_addr dst_addr; }; /* struct holding a ctdb_sock_addr and an interface name, used to add/remove public addresses */ struct ctdb_control_ip_iface { ctdb_sock_addr addr; uint32_t mask; uint32_t len; char iface[1]; }; /* struct holding a ctdb_sock_addr and an interface name, used for send_gratious_arp */ struct ctdb_control_gratious_arp { ctdb_sock_addr addr; uint32_t mask; uint32_t len; char iface[1]; }; /* persistent store control - update this record on all other nodes */ struct ctdb_control_persistent_store { uint32_t db_id; uint32_t len; uint8_t data[1]; }; /* structure used for CTDB_SRVID_NODE_FLAGS_CHANGED */ struct ctdb_node_flag_change { uint32_t pnn; uint32_t new_flags; uint32_t old_flags; }; /* struct for admin setting a ban */ struct ctdb_ban_info { uint32_t pnn; uint32_t ban_time; }; enum call_state {CTDB_CALL_WAIT, CTDB_CALL_DONE, CTDB_CALL_ERROR}; #define CTDB_LMASTER_ANY 0xffffffff /* state of a in-progress ctdb call */ struct ctdb_call_state { struct ctdb_call_state *next, *prev; enum call_state state; uint32_t reqid; struct ctdb_req_call *c; struct ctdb_db_context *ctdb_db; const char *errmsg; struct ctdb_call *call; uint32_t generation; struct { void (*fn)(struct ctdb_call_state *); void *private_data; } async; }; /* used for fetch_lock */ struct ctdb_fetch_handle { struct ctdb_db_context *ctdb_db; TDB_DATA key; TDB_DATA *data; struct ctdb_ltdb_header header; }; /* internal prototypes */ void ctdb_set_error(struct ctdb_context *ctdb, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); void ctdb_fatal(struct ctdb_context *ctdb, const char *msg); void ctdb_die(struct ctdb_context *ctdb, const char *msg); void ctdb_external_trace(void); bool ctdb_same_address(struct ctdb_address *a1, struct ctdb_address *a2); int ctdb_parse_address(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, const char *str, struct ctdb_address *address); bool ctdb_same_ip(const ctdb_sock_addr *ip1, const ctdb_sock_addr *ip2); bool ctdb_same_sockaddr(const ctdb_sock_addr *ip1, const ctdb_sock_addr *ip2); uint32_t ctdb_hash(const TDB_DATA *key); uint32_t ctdb_hash_string(const char *str); void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_request_message(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_reply_error(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); uint32_t ctdb_lmaster(struct ctdb_context *ctdb, const TDB_DATA *key); int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx, TDB_DATA *data); int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data); int ctdb_ltdb_delete(struct ctdb_db_context *ctdb_db, TDB_DATA key); int ctdb_ltdb_fetch_with_header(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx, TDB_DATA *data); int32_t ctdb_control_start_persistent_update(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA recdata); int32_t ctdb_control_cancel_persistent_update(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA recdata); void ctdb_queue_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_queue_packet_opcode(struct ctdb_context *ctdb, struct ctdb_req_header *hdr, unsigned opcode); int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_req_header *hdr, void (*recv_pkt)(void *, struct ctdb_req_header *), void *recv_context, bool ignore_generation); int ctdb_ltdb_lock_fetch_requeue(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, struct ctdb_req_header *hdr, TDB_DATA *data, void (*recv_pkt)(void *, struct ctdb_req_header *), void *recv_context, bool ignore_generation); void ctdb_input_pkt(struct ctdb_context *ctdb, struct ctdb_req_header *); struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call, struct ctdb_ltdb_header *header, TDB_DATA *data); int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork, bool use_syslog); struct ctdb_call_state *ctdbd_call_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call); int ctdbd_call_recv(struct ctdb_call_state *state, struct ctdb_call *call); /* queue a packet for sending */ int ctdb_queue_send(struct ctdb_queue *queue, uint8_t *data, uint32_t length); /* setup the fd used by the queue */ int ctdb_queue_set_fd(struct ctdb_queue *queue, int fd); /* setup a packet queue on a socket */ struct ctdb_queue *ctdb_queue_setup(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, int fd, int alignment, ctdb_queue_cb_fn_t callback, void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(7,8); /* allocate a packet for use in client<->daemon communication */ struct ctdb_req_header *_ctdbd_allocate_pkt(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, enum ctdb_operation operation, size_t length, size_t slength, const char *type); #define ctdbd_allocate_pkt(ctdb, mem_ctx, operation, length, type) \ (type *)_ctdbd_allocate_pkt(ctdb, mem_ctx, operation, length, sizeof(type), #type) struct ctdb_req_header *_ctdb_transport_allocate(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, enum ctdb_operation operation, size_t length, size_t slength, const char *type); #define ctdb_transport_allocate(ctdb, mem_ctx, operation, length, type) \ (type *)_ctdb_transport_allocate(ctdb, mem_ctx, operation, length, sizeof(type), #type) int ctdb_queue_length(struct ctdb_queue *queue); /* lock a record in the ltdb, given a key */ int ctdb_ltdb_lock(struct ctdb_db_context *ctdb_db, TDB_DATA key); /* unlock a record in the ltdb, given a key */ int ctdb_ltdb_unlock(struct ctdb_db_context *ctdb_db, TDB_DATA key); /* make a ctdb call to the local daemon - async send. Called from client context. This constructs a ctdb_call request and queues it for processing. This call never blocks. */ struct ctdb_call_state *ctdb_client_call_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call); /* make a recv call to the local ctdb daemon - called from client context This is called when the program wants to wait for a ctdb_call to complete and get the results. This call will block unless the call has already completed. */ int ctdb_client_call_recv(struct ctdb_call_state *state, struct ctdb_call *call); int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t vnn, uint64_t srvid, TDB_DATA data); /* send a ctdb message */ int ctdb_daemon_send_message(struct ctdb_context *ctdb, uint32_t pnn, uint64_t srvid, TDB_DATA data); struct ctdb_call_state *ctdb_daemon_call_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call); int ctdb_daemon_call_recv(struct ctdb_call_state *state, struct ctdb_call *call); struct ctdb_call_state *ctdb_daemon_call_send_remote(struct ctdb_db_context *ctdb_db, struct ctdb_call *call, struct ctdb_ltdb_header *header); int ctdb_call_local(struct ctdb_db_context *ctdb_db, struct ctdb_call *call, struct ctdb_ltdb_header *header, TALLOC_CTX *mem_ctx, TDB_DATA *data, bool updatetdb); #define ctdb_reqid_find(ctdb, reqid, type) (type *)_ctdb_reqid_find(ctdb, reqid, #type, __location__) void ctdb_recv_raw_pkt(void *p, uint8_t *data, uint32_t length); int ctdb_socket_connect(struct ctdb_context *ctdb); void ctdb_client_read_cb(uint8_t *data, size_t cnt, void *args); #define CTDB_BAD_REQID ((uint32_t)-1) uint32_t ctdb_reqid_new(struct ctdb_context *ctdb, void *state); void *_ctdb_reqid_find(struct ctdb_context *ctdb, uint32_t reqid, const char *type, const char *location); void ctdb_reqid_remove(struct ctdb_context *ctdb, uint32_t reqid); void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); int ctdb_daemon_send_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, uint32_t opcode, uint32_t client_id, uint32_t flags, TDB_DATA data, ctdb_control_callback_fn_t callback, void *private_data); int32_t ctdb_control_db_attach(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata, uint64_t tdb_flags, bool persistent, uint32_t client_id, struct ctdb_req_control *c, bool *async_reply); int ctdb_daemon_set_call(struct ctdb_context *ctdb, uint32_t db_id, ctdb_fn_t fn, int id); int ctdb_control(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, uint32_t opcode, uint32_t flags, TDB_DATA data, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status, struct timeval *timeout, char **errormsg); int ctdb_control_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int32_t *status, char **errormsg); struct ctdb_client_control_state * ctdb_control_send(struct ctdb_context *ctdb, uint32_t destnode, uint64_t srvid, uint32_t opcode, uint32_t flags, TDB_DATA data, TALLOC_CTX *mem_ctx, struct timeval *timeout, char **errormsg); #define CHECK_CONTROL_DATA_SIZE(size) do { \ if (indata.dsize != size) { \ DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected %u\n", \ opcode, (unsigned)indata.dsize, (unsigned)size)); \ return -1; \ } \ } while (0) #define CHECK_CONTROL_MIN_DATA_SIZE(size) do { \ if (indata.dsize < size) { \ DEBUG(0,(__location__ " Invalid data size in opcode %u. Got %u expected >= %u\n", \ opcode, (unsigned)indata.dsize, (unsigned)size)); \ return -1; \ } \ } while (0) int ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata); int ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata); int ctdb_control_getdbmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata); int ctdb_control_getnodemapv4(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata); int ctdb_control_getnodemap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata); int ctdb_control_writerecord(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata); /* structure used for pulldb control */ struct ctdb_control_pulldb { uint32_t db_id; uint32_t lmaster; }; /* structure used for sending lists of records */ struct ctdb_marshall_buffer { uint32_t db_id; uint32_t count; uint8_t data[1]; }; /* structure for setting a tunable */ struct ctdb_control_set_tunable { uint32_t value; uint32_t length; uint8_t name[1]; }; /* structure for getting a tunable */ struct ctdb_control_get_tunable { uint32_t length; uint8_t name[1]; }; /* structure for listing tunables */ struct ctdb_control_list_tunable { uint32_t length; /* returns a : separated list of tunable names */ uint8_t data[1]; }; struct ctdb_node_and_flagsv4 { uint32_t pnn; uint32_t flags; struct sockaddr_in sin; }; struct ctdb_node_mapv4 { uint32_t num; struct ctdb_node_and_flagsv4 nodes[1]; }; struct ctdb_control_wipe_database { uint32_t db_id; uint32_t transaction_id; }; /* state of a in-progress ctdb call in client */ struct ctdb_client_call_state { enum call_state state; uint32_t reqid; struct ctdb_db_context *ctdb_db; struct ctdb_call *call; struct { void (*fn)(struct ctdb_client_call_state *); void *private_data; } async; }; int32_t ctdb_control_traverse_start_ext(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata, uint32_t srcnode, uint32_t client_id); int32_t ctdb_control_traverse_start(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata, uint32_t srcnode, uint32_t client_id); int32_t ctdb_control_traverse_all(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata); int32_t ctdb_control_traverse_all_ext(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata); int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata); int32_t ctdb_control_traverse_kill(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata, uint32_t srcnode); int ctdb_dispatch_message(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data); bool ctdb_check_message_handler(struct ctdb_context *ctdb, uint64_t srvid); int daemon_register_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid); int ctdb_deregister_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data); int daemon_deregister_message_handler(struct ctdb_context *ctdb, uint32_t client_id, uint64_t srvid); int daemon_check_srvids(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); int32_t ctdb_ltdb_enable_seqnum(struct ctdb_context *ctdb, uint32_t db_id); int32_t ctdb_ltdb_update_seqnum(struct ctdb_context *ctdb, uint32_t db_id, uint32_t srcnode); struct ctdb_rec_data *ctdb_marshall_record(TALLOC_CTX *mem_ctx, uint32_t reqid, TDB_DATA key, struct ctdb_ltdb_header *, TDB_DATA data); struct ctdb_rec_data *ctdb_marshall_loop_next(struct ctdb_marshall_buffer *m, struct ctdb_rec_data *r, uint32_t *reqid, struct ctdb_ltdb_header *header, TDB_DATA *key, TDB_DATA *data); int32_t ctdb_control_pull_db(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); int32_t ctdb_control_push_db(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_set_recmode(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA indata, bool *async_reply, const char **errormsg); void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata, int32_t status, const char *errormsg); int32_t ctdb_control_freeze(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply); int32_t ctdb_control_thaw(struct ctdb_context *ctdb, uint32_t priority); int ctdb_start_recoverd(struct ctdb_context *ctdb); void ctdb_stop_recoverd(struct ctdb_context *ctdb); uint32_t ctdb_get_num_active_nodes(struct ctdb_context *ctdb); void ctdb_disable_monitoring(struct ctdb_context *ctdb); void ctdb_enable_monitoring(struct ctdb_context *ctdb); void ctdb_stop_monitoring(struct ctdb_context *ctdb); void ctdb_start_monitoring(struct ctdb_context *ctdb); void ctdb_start_tcp_tickle_update(struct ctdb_context *ctdb); void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode); void ctdb_start_keepalive(struct ctdb_context *ctdb); void ctdb_stop_keepalive(struct ctdb_context *ctdb); int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA data, bool *async_reply); void ctdb_daemon_cancel_controls(struct ctdb_context *ctdb, struct ctdb_node *node); void ctdb_call_resend_all(struct ctdb_context *ctdb); void ctdb_node_dead(struct ctdb_node *node); void ctdb_node_connected(struct ctdb_node *node); bool ctdb_blocking_freeze(struct ctdb_context *ctdb); void ctdb_set_scheduler(struct ctdb_context *ctdb); void ctdb_restore_scheduler(struct ctdb_context *ctdb); struct tevent_signal *ctdb_init_sigchld(struct ctdb_context *ctdb); void ctdb_track_child(struct ctdb_context *ctdb, pid_t pid); pid_t ctdb_fork(struct ctdb_context *ctdb); pid_t ctdb_fork_no_free_ringbuffer(struct ctdb_context *ctdb); void ctdb_set_child_info(TALLOC_CTX *mem_ctx, const char *child_name_fmt, ...); bool ctdb_is_child_process(void); int ctdb_kill(struct ctdb_context *ctdb, pid_t pid, int signum); int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA indata, bool *async_reply); int32_t ctdb_control_takeover_ipv4(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA indata, bool *async_reply); int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA indata, bool *async_reply); int32_t ctdb_control_release_ipv4(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA indata, bool *async_reply); int32_t ctdb_control_ipreallocated(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply); int32_t ctdb_control_start_recovery(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply); int32_t ctdb_control_end_recovery(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply); struct ctdb_public_ipv4 { uint32_t pnn; struct sockaddr_in sin; }; int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_public_ip *ip); int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_public_ip *ip); struct ctdb_all_public_ipsv4 { uint32_t num; struct ctdb_public_ipv4 ips[1]; }; int32_t ctdb_control_get_public_ipsv4(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata); int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata); int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips); #define CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE 0x00010000 int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, uint32_t flags, struct ctdb_all_public_ips **ips); int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips); struct ctdb_control_iface_info { char name[CTDB_IFACE_SIZE+2]; uint16_t link_state; uint32_t references; }; struct ctdb_control_public_ip_info { struct ctdb_public_ip ip; uint32_t active_idx; uint32_t num; struct ctdb_control_iface_info ifaces[1]; }; struct ctdb_control_get_ifaces { uint32_t num; struct ctdb_control_iface_info ifaces[1]; }; int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA indata, TDB_DATA *outdata); int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata); int32_t ctdb_control_set_iface_link(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA indata); int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const ctdb_sock_addr *addr, struct ctdb_control_public_ip_info **info); int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_control_get_ifaces **ifaces); int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const struct ctdb_control_iface_info *info); /* from takeover/system.c */ uint32_t uint16_checksum(uint16_t *data, size_t n); int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface); bool ctdb_sys_have_ip(ctdb_sock_addr *addr); char *ctdb_sys_find_ifname(ctdb_sock_addr *addr); bool ctdb_sys_check_iface_exists(const char *iface); int ctdb_get_peer_pid(const int fd, pid_t *peer_pid); int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, const ctdb_sock_addr *src, uint32_t seq, uint32_t ack, int rst); /* Details of a byte range lock */ struct ctdb_lock_info { ino_t inode; off_t start, end; bool waiting; bool read_only; }; char *ctdb_get_process_name(pid_t pid); int ctdb_set_process_name(const char *name); bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info); bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid); typedef void (*client_async_callback)(struct ctdb_context *ctdb, uint32_t node_pnn, int32_t res, TDB_DATA outdata, void *callback_data); int ctdb_set_public_addresses(struct ctdb_context *ctdb, bool check_addresses); int ctdb_set_single_public_ip(struct ctdb_context *ctdb, const char *iface, const char *ip); int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script); int ctdb_set_notification_script(struct ctdb_context *ctdb, const char *script); int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, uint32_t *force_rebalance_nodes, client_async_callback fail_callback, void *callback_data); int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata); int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tcp_update_needed); int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn); int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); int32_t ctdb_control_set_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata); void ctdb_takeover_client_destructor_hook(struct ctdb_client *client); int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_eventscript_call call); int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_eventscript_call call, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); int ctdb_event_script_callback(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, void (*callback)(struct ctdb_context *, int, void *), void *private_data, bool from_user, enum ctdb_eventscript_call call, const char *fmt, ...) PRINTF_ATTRIBUTE(7,8); void ctdb_release_all_ips(struct ctdb_context *ctdb); void set_nonblocking(int fd); void set_close_on_exec(int fd); bool ctdb_recovery_lock(struct ctdb_context *ctdb, bool keep); int ctdb_set_recovery_lock_file(struct ctdb_context *ctdb, const char *file); int32_t ctdb_control_get_tunable(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); int32_t ctdb_control_set_tunable(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_list_tunables(struct ctdb_context *ctdb, TDB_DATA *outdata); int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); int32_t ctdb_control_receive_records(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb, TDB_DATA indata); void ctdb_tunables_set_defaults(struct ctdb_context *ctdb); int32_t ctdb_control_modflags(struct ctdb_context *ctdb, TDB_DATA indata); int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_tunable *tunables); void ctdb_start_freeze(struct ctdb_context *ctdb, uint32_t priority); bool parse_ip_mask(const char *s, const char *iface, ctdb_sock_addr *addr, unsigned *mask); bool parse_ip_port(const char *s, ctdb_sock_addr *addr); bool parse_ip(const char *s, const char *iface, unsigned port, ctdb_sock_addr *addr); bool parse_ipv4(const char *s, unsigned port, struct sockaddr_in *sin); int ctdb_sys_open_capture_socket(const char *iface, void **private_data); int ctdb_sys_close_capture_socket(void *private_data); int ctdb_sys_read_tcp_packet(int s, void *private_data, ctdb_sock_addr *src, ctdb_sock_addr *dst, uint32_t *ack_seq, uint32_t *seq); int ctdb_ctrl_killtcp(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_control_killtcp *killtcp); int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_control_ip_iface *pub); int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_control_ip_iface *pub); int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, ctdb_sock_addr *addr, const char *ifname); int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, ctdb_sock_addr *addr, struct ctdb_control_tcp_tickle_list **list); int32_t ctdb_control_register_server_id(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata); int32_t ctdb_control_check_server_id(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_unregister_server_id(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_get_server_id_list(struct ctdb_context *ctdb, TDB_DATA *outdata); int32_t ctdb_control_uptime(struct ctdb_context *ctdb, TDB_DATA *outdata); int ctdb_attach_databases(struct ctdb_context *ctdb); int32_t ctdb_control_persistent_store(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA recdata, bool *async_reply); int32_t ctdb_control_update_record(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA recdata, bool *async_reply); int32_t ctdb_control_trans2_commit(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA recdata, bool *async_reply); int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA recdata, bool *async_reply); void ctdb_persistent_finish_trans3_commits(struct ctdb_context *ctdb); int32_t ctdb_control_transaction_start(struct ctdb_context *ctdb, uint32_t id); int32_t ctdb_control_transaction_commit(struct ctdb_context *ctdb, uint32_t id); int32_t ctdb_control_transaction_cancel(struct ctdb_context *ctdb); int32_t ctdb_control_wipe_database(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_db_set_healthy(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_db_get_health(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); int ctdb_vacuum(struct ctdb_context *ctdb, int argc, const char **argv); int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv); void ctdb_block_signal(int signum); void ctdb_unblock_signal(int signum); int32_t ctdb_monitoring_mode(struct ctdb_context *ctdb); bool ctdb_stopped_monitoring(struct ctdb_context *ctdb); int ctdb_set_child_logging(struct ctdb_context *ctdb); void ctdb_lockdown_memory(struct ctdb_context *ctdb); struct client_async_data { enum ctdb_controls opcode; bool dont_log_errors; uint32_t count; uint32_t fail_count; client_async_callback callback; client_async_callback fail_callback; void *callback_data; }; void ctdb_client_async_add(struct client_async_data *data, struct ctdb_client_control_state *state); int ctdb_client_async_wait(struct ctdb_context *ctdb, struct client_async_data *data); int ctdb_client_async_control(struct ctdb_context *ctdb, enum ctdb_controls opcode, uint32_t *nodes, uint64_t srvid, struct timeval timeout, bool dont_log_errors, TDB_DATA data, client_async_callback client_callback, client_async_callback fail_callback, void *callback_data); void ctdb_load_nodes_file(struct ctdb_context *ctdb); int ctdb_control_reload_nodes_file(struct ctdb_context *ctdb, uint32_t opcode); int32_t ctdb_dump_memory(struct ctdb_context *ctdb, TDB_DATA *outdata); int32_t ctdb_control_get_capabilities(struct ctdb_context *ctdb, TDB_DATA *outdata); int32_t ctdb_control_trans2_finished(struct ctdb_context *ctdb, struct ctdb_req_control *c); int32_t ctdb_control_trans2_error(struct ctdb_context *ctdb, struct ctdb_req_control *c); int32_t ctdb_control_trans2_active(struct ctdb_context *ctdb, struct ctdb_req_control *c, uint32_t db_id); char *ctdb_addr_to_str(ctdb_sock_addr *addr); unsigned ctdb_addr_to_port(ctdb_sock_addr *addr); void ctdb_canonicalize_ip(const ctdb_sock_addr *ip, ctdb_sock_addr *cip); int32_t ctdb_control_recd_ping(struct ctdb_context *ctdb); int32_t ctdb_control_set_recmaster(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata); extern int script_log_level; extern bool fast_start; extern const char *ctdbd_pidfile; int32_t ctdb_control_get_event_script_status(struct ctdb_context *ctdb, uint32_t call_type, TDB_DATA *outdata); int ctdb_log_event_script_output(struct ctdb_context *ctdb, char *str, uint16_t len); int ctdb_ctrl_report_recd_lock_latency(struct ctdb_context *ctdb, struct timeval timeout, double latency); int32_t ctdb_control_stop_node(struct ctdb_context *ctdb); int32_t ctdb_control_continue_node(struct ctdb_context *ctdb); void ctdb_stop_vacuuming(struct ctdb_context *ctdb); int ctdb_vacuum_init(struct ctdb_db_context *ctdb_db); int32_t ctdb_control_enable_script(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_disable_script(struct ctdb_context *ctdb, TDB_DATA indata); void ctdb_local_node_got_banned(struct ctdb_context *ctdb); int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata); int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata); void ctdb_ban_self(struct ctdb_context *ctdb); int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata); int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata); int start_syslog_daemon(struct ctdb_context *ctdb); /* Where to send the log messages back to */ struct ctdb_get_log_addr { uint32_t pnn; uint64_t srvid; int32_t level; }; extern int log_ringbuf_size; void ctdb_collect_log(struct ctdb_context *ctdb, struct ctdb_get_log_addr *log_addr); void ctdb_clear_log(struct ctdb_context *ctdb); int32_t ctdb_control_get_log(struct ctdb_context *ctdb, TDB_DATA addr); int32_t ctdb_control_clear_log(struct ctdb_context *ctdb); void ctdb_log_ringbuffer_free(void); struct ctdb_log_state *ctdb_fork_with_logging(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb, const char *log_prefix, void (*logfn)(const char *, uint16_t, void *), void *logfn_private, pid_t *pid); int32_t ctdb_control_process_exists(struct ctdb_context *ctdb, pid_t pid); struct ctdb_client *ctdb_find_client_by_pid(struct ctdb_context *ctdb, pid_t pid); int32_t ctdb_control_get_db_seqnum(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata); int ctdb_load_persistent_health(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db); int ctdb_update_persistent_health(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, const char *reason,/* NULL means healthy */ int num_healthy_nodes); int ctdb_recheck_persistent_health(struct ctdb_context *ctdb); void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event); void ctdb_fault_setup(void); int verify_remote_ip_allocation(struct ctdb_context *ctdb, struct ctdb_all_public_ips *ips, uint32_t pnn); int update_ip_assignment_tree(struct ctdb_context *ctdb, struct ctdb_public_ip *ip); int ctdb_init_tevent_logging(struct ctdb_context *ctdb); int ctdb_statistics_init(struct ctdb_context *ctdb); int32_t ctdb_control_get_stat_history(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata); int ctdb_deferred_drop_all_ips(struct ctdb_context *ctdb); int ctdb_process_deferred_attach(struct ctdb_context *ctdb); /** * structure to pass to a schedule_for_deletion_control */ struct ctdb_control_schedule_for_deletion { uint32_t db_id; struct ctdb_ltdb_header hdr; uint32_t keylen; uint8_t key[1]; /* key[] */ }; int32_t ctdb_control_schedule_for_deletion(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_local_schedule_for_deletion(struct ctdb_db_context *ctdb_db, const struct ctdb_ltdb_header *hdr, TDB_DATA key); void ctdb_local_remove_from_delete_queue(struct ctdb_db_context *ctdb_db, const struct ctdb_ltdb_header *hdr, const TDB_DATA key); struct ctdb_ltdb_header *ctdb_header_from_record_handle(struct ctdb_record_handle *h); int ctdb_trackingdb_add_pnn(struct ctdb_context *ctdb, TDB_DATA *data, uint32_t pnn); typedef void (*ctdb_trackingdb_cb)(struct ctdb_context *ctdb, uint32_t pnn, void *private_data); void ctdb_trackingdb_traverse(struct ctdb_context *ctdb, TDB_DATA data, ctdb_trackingdb_cb cb, void *private_data); int ctdb_start_revoke_ro_record(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data); typedef void (*deferred_requeue_fn)(void *call_context, struct ctdb_req_header *hdr); int ctdb_add_revoke_deferred_call(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_req_header *hdr, deferred_requeue_fn fn, void *call_context); int ctdb_set_db_readonly(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db); int ctdb_null_func(struct ctdb_call_info *call); int ctdb_fetch_func(struct ctdb_call_info *call); int ctdb_fetch_with_header_func(struct ctdb_call_info *call); int32_t ctdb_control_get_db_statistics(struct ctdb_context *ctdb, uint32_t db_id, TDB_DATA *outdata); int ctdb_set_db_sticky(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db); /* description for a message to reload all ips via recovery master/daemon */ struct reloadips_all_reply { uint32_t pnn; uint64_t srvid; }; int32_t ctdb_control_reload_public_ips(struct ctdb_context *ctdb, struct ctdb_req_control *c, bool *async_reply); int ctdb_start_monitoring_interfaces(struct ctdb_context *ctdb); /* from server/ctdb_lock.c */ struct lock_request; int ctdb_lockall_mark_prio(struct ctdb_context *ctdb, uint32_t priority); int ctdb_lockall_unmark_prio(struct ctdb_context *ctdb, uint32_t priority); void ctdb_lock_free_request_context(struct lock_request *lock_req); struct lock_request *ctdb_lock_record(struct ctdb_db_context *ctdb_db, TDB_DATA key, bool auto_mark, void (*callback)(void *, bool), void *private_data); struct lock_request *ctdb_lock_db(struct ctdb_db_context *ctdb_db, bool auto_mark, void (*callback)(void *, bool), void *private_data); struct lock_request *ctdb_lock_alldb_prio(struct ctdb_context *ctdb, uint32_t priority, bool auto_mark, void (*callback)(void *, bool), void *private_data); struct lock_request *ctdb_lock_alldb(struct ctdb_context *ctdb, bool auto_mark, void (*callback)(void *, bool), void *private_data); int mkdir_p(const char *dir, int mode); void ctdb_mkdir_p_or_die(struct ctdb_context *ctdb, const char *dir, int mode); #endif ctdb-2.5.1.dfsg/include/idtree.h0000644000175000017500000000056412245023514016302 0ustar mathieumathieustruct idr_context *idr_init(TALLOC_CTX *mem_ctx); int idr_get_new(struct idr_context *idp, void *ptr, int limit); int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit); int idr_get_new_random(struct idr_context *idp, void *ptr, int limit); void *idr_find(struct idr_context *idp, int id); int idr_remove(struct idr_context *idp, int id); ctdb-2.5.1.dfsg/include/ctdb_protocol.h0000644000175000017500000005307012245023514017663 0ustar mathieumathieu/* ctdb database library Copyright (C) Andrew Tridgell 2006 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #ifndef _CTDB_PROTOCOL_H #define _CTDB_PROTOCOL_H /* location of daemon socket, set at configure time */ #ifdef SOCKPATH #define CTDB_PATH SOCKPATH #else #define CTDB_PATH "/var/run/ctdb/ctdbd.socket" #endif /* default ctdb port number */ #define CTDB_PORT 4379 /* we must align packets to ensure ctdb works on all architectures (eg. sparc) */ #define CTDB_DS_ALIGNMENT 8 #define CTDB_NULL_FUNC 0xFF000001 #define CTDB_FETCH_FUNC 0xFF000002 #define CTDB_FETCH_WITH_HEADER_FUNC 0xFF000003 struct ctdb_call { int call_id; TDB_DATA key; TDB_DATA call_data; TDB_DATA reply_data; uint32_t status; #define CTDB_IMMEDIATE_MIGRATION 0x00000001 #define CTDB_CALL_FLAG_VACUUM_MIGRATION 0x00000002 #define CTDB_WANT_READONLY 0x00000004 uint32_t flags; }; /* structure passed to a ctdb call backend function */ struct ctdb_call_info { TDB_DATA key; /* record key */ struct ctdb_ltdb_header *header; TDB_DATA record_data; /* current data in the record */ TDB_DATA *new_data; /* optionally updated record data */ TDB_DATA *call_data; /* optionally passed from caller */ TDB_DATA *reply_data; /* optionally returned by function */ uint32_t status; /* optional reply status - defaults to zero */ }; #define CTDB_ERR_INVALID 1 #define CTDB_ERR_NOMEM 2 /* ctdb flags */ #define CTDB_FLAG_TORTURE (1<<1) /* a message handler ID meaning "give me all messages" */ #define CTDB_SRVID_ALL (~(uint64_t)0) /* srvid type : RECOVERY */ #define CTDB_SRVID_RECOVERY 0xF100000000000000LL /* a message handler ID meaning that the cluster has been reconfigured */ #define CTDB_SRVID_RECONFIGURE 0xF200000000000000LL /* a message handler ID meaning that an IP address has been released */ #define CTDB_SRVID_RELEASE_IP 0xF300000000000000LL /* a message handler ID meaning that an IP address has been taken */ #define CTDB_SRVID_TAKE_IP 0xF301000000000000LL /* a message ID to set the node flags in the recovery daemon */ #define CTDB_SRVID_SET_NODE_FLAGS 0xF400000000000000LL /* a message ID to ask the recovery daemon to update the expected node assignment for a public ip */ #define CTDB_SRVID_RECD_UPDATE_IP 0xF500000000000000LL /* a message to tell the recovery daemon to fetch a set of records */ #define CTDB_SRVID_VACUUM_FETCH 0xF700000000000000LL /* a message to tell the recovery daemon to write a talloc memdump to the log */ #define CTDB_SRVID_MEM_DUMP 0xF800000000000000LL /* A message id used to ask the recover daemon to send logs */ #define CTDB_SRVID_GETLOG 0xF801000000000000LL /* A message id used to ask the recover daemon to send logs */ #define CTDB_SRVID_CLEARLOG 0xF802000000000000LL /* a message ID to get the recovery daemon to push the node flags out */ #define CTDB_SRVID_PUSH_NODE_FLAGS 0xF900000000000000LL /* a message ID to get the recovery daemon to reload the nodes file */ #define CTDB_SRVID_RELOAD_NODES 0xFA00000000000000LL /* a message ID to get the recovery daemon to perform a takeover run */ #define CTDB_SRVID_TAKEOVER_RUN 0xFB00000000000000LL /* request recovery daemon to rebalance ips for a node. input is uint32_t for the node id. */ #define CTDB_SRVID_REBALANCE_NODE 0xFB01000000000000LL /* A message handler ID to stop takeover runs from occurring */ #define CTDB_SRVID_DISABLE_TAKEOVER_RUNS 0xFB03000000000000LL /* A message id to ask the recovery daemon to temporarily disable the public ip checks */ #define CTDB_SRVID_DISABLE_IP_CHECK 0xFC00000000000000LL /* A dummy port used for sending back ipreallocate resposnes to the main daemon */ #define CTDB_SRVID_TAKEOVER_RUN_RESPONSE 0xFD00000000000000LL /* A range of ports reserved for registering a PID (top 8 bits) * All ports matching the 8 top bits are reserved for exclusive use by * registering a SRVID that matches the process-id of the requesting process */ #define CTDB_SRVID_PID_RANGE 0x0000000000000000LL /* A range of ports reserved for samba (top 8 bits) * All ports matching the 8 top bits are reserved for exclusive use by * CIFS server */ #define CTDB_SRVID_SAMBA_NOTIFY 0xFE00000000000000LL #define CTDB_SRVID_SAMBA_RANGE 0xFE00000000000000LL /* A range of ports reserved for a CTDB NFS server (top 8 bits) * All ports matching the 8 top bits are reserved for exclusive use by * NFS server */ #define CTDB_SRVID_NFSD_RANGE 0xEE00000000000000LL /* A range of ports reserved for a CTDB ISCSI server (top 8 bits) * All ports matching the 8 top bits are reserved for exclusive use by * ISCSI server */ #define CTDB_SRVID_ISCSID_RANGE 0xDE00000000000000LL /* A range of ports reserved for testing (top 8 bits) * All ports matching the 8 top bits are reserved for exclusive use by * test applications */ #define CTDB_SRVID_TEST_RANGE 0xCE00000000000000LL /* Range of ports reserved for traversals */ #define CTDB_SRVID_TRAVERSE_RANGE 0xBE00000000000000LL /* used on the domain socket, send a pdu to the local daemon */ #define CTDB_CURRENT_NODE 0xF0000001 /* send a broadcast to all nodes in the cluster, active or not */ #define CTDB_BROADCAST_ALL 0xF0000002 /* send a broadcast to all nodes in the current vnn map */ #define CTDB_BROADCAST_VNNMAP 0xF0000003 /* send a broadcast to all connected nodes */ #define CTDB_BROADCAST_CONNECTED 0xF0000004 /* send a broadcast to selected connected nodes */ #define CTDB_MULTICAST 0xF0000005 /* the key used for transaction locking on persistent databases */ #define CTDB_TRANSACTION_LOCK_KEY "__transaction_lock__" /* the key used to store persistent db sequence number */ #define CTDB_DB_SEQNUM_KEY "__db_sequence_number__" #define MONITOR_SCRIPT_OK 0 #define MONITOR_SCRIPT_TIMEOUT 1 #define MAX_SCRIPT_NAME 31 #define MAX_SCRIPT_OUTPUT 511 struct ctdb_script_wire { char name[MAX_SCRIPT_NAME+1]; struct timeval start; struct timeval finished; int32_t status; char output[MAX_SCRIPT_OUTPUT+1]; }; struct ctdb_scripts_wire { uint32_t num_scripts; struct ctdb_script_wire scripts[1]; }; /* different calls to event scripts. */ enum ctdb_eventscript_call { CTDB_EVENT_INIT, /* CTDB starting up: no args */ CTDB_EVENT_SETUP, /* CTDB starting up after transport is readdy: no args. */ CTDB_EVENT_STARTUP, /* CTDB starting up after initial recovery: no args. */ CTDB_EVENT_START_RECOVERY, /* CTDB recovery starting: no args. */ CTDB_EVENT_RECOVERED, /* CTDB recovery finished: no args. */ CTDB_EVENT_TAKE_IP, /* IP taken: interface, IP address, netmask bits. */ CTDB_EVENT_RELEASE_IP, /* IP released: interface, IP address, netmask bits. */ CTDB_EVENT_STOPPED, /* Deprecated, do not use. */ CTDB_EVENT_MONITOR, /* Please check if service is healthy: no args. */ CTDB_EVENT_STATUS, /* Report service status: no args. */ CTDB_EVENT_SHUTDOWN, /* CTDB shutting down: no args. */ CTDB_EVENT_RELOAD, /* magic */ CTDB_EVENT_UPDATE_IP, /* IP updating: old interface, new interface, IP address, netmask bits. */ CTDB_EVENT_IPREALLOCATED, /* when a takeover_run() completes */ CTDB_EVENT_MAX }; /* Mapping from enum to names. */ extern const char *ctdb_eventscript_call_names[]; /* operation IDs */ enum ctdb_operation { CTDB_REQ_CALL = 0, CTDB_REPLY_CALL = 1, CTDB_REQ_DMASTER = 2, CTDB_REPLY_DMASTER = 3, CTDB_REPLY_ERROR = 4, CTDB_REQ_MESSAGE = 5, /* #6 removed */ CTDB_REQ_CONTROL = 7, CTDB_REPLY_CONTROL = 8, CTDB_REQ_KEEPALIVE = 9, }; #define CTDB_MAGIC 0x43544442 /* CTDB */ #define CTDB_VERSION 1 enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0, CTDB_CONTROL_STATISTICS = 1, /* #2 removed */ CTDB_CONTROL_PING = 3, CTDB_CONTROL_GETDBPATH = 4, CTDB_CONTROL_GETVNNMAP = 5, CTDB_CONTROL_SETVNNMAP = 6, CTDB_CONTROL_GET_DEBUG = 7, CTDB_CONTROL_SET_DEBUG = 8, CTDB_CONTROL_GET_DBMAP = 9, CTDB_CONTROL_GET_NODEMAPv4 = 10, /* obsolete */ CTDB_CONTROL_SET_DMASTER = 11, /* obsolete */ /* #12 removed */ CTDB_CONTROL_PULL_DB = 13, CTDB_CONTROL_PUSH_DB = 14, CTDB_CONTROL_GET_RECMODE = 15, CTDB_CONTROL_SET_RECMODE = 16, CTDB_CONTROL_STATISTICS_RESET = 17, CTDB_CONTROL_DB_ATTACH = 18, CTDB_CONTROL_SET_CALL = 19, CTDB_CONTROL_TRAVERSE_START = 20, CTDB_CONTROL_TRAVERSE_ALL = 21, CTDB_CONTROL_TRAVERSE_DATA = 22, CTDB_CONTROL_REGISTER_SRVID = 23, CTDB_CONTROL_DEREGISTER_SRVID = 24, CTDB_CONTROL_GET_DBNAME = 25, CTDB_CONTROL_ENABLE_SEQNUM = 26, CTDB_CONTROL_UPDATE_SEQNUM = 27, /* #28 removed */ CTDB_CONTROL_DUMP_MEMORY = 29, CTDB_CONTROL_GET_PID = 30, CTDB_CONTROL_GET_RECMASTER = 31, CTDB_CONTROL_SET_RECMASTER = 32, CTDB_CONTROL_FREEZE = 33, CTDB_CONTROL_THAW = 34, CTDB_CONTROL_GET_PNN = 35, CTDB_CONTROL_SHUTDOWN = 36, CTDB_CONTROL_GET_MONMODE = 37, /* #38 removed */ /* #39 removed */ /* #40 removed */ /* #41 removed */ CTDB_CONTROL_TAKEOVER_IPv4 = 42, /* obsolete */ CTDB_CONTROL_RELEASE_IPv4 = 43, /* obsolete */ CTDB_CONTROL_TCP_CLIENT = 44, CTDB_CONTROL_TCP_ADD = 45, CTDB_CONTROL_TCP_REMOVE = 46, CTDB_CONTROL_STARTUP = 47, CTDB_CONTROL_SET_TUNABLE = 48, CTDB_CONTROL_GET_TUNABLE = 49, CTDB_CONTROL_LIST_TUNABLES = 50, CTDB_CONTROL_GET_PUBLIC_IPSv4 = 51, /* obsolete */ CTDB_CONTROL_MODIFY_FLAGS = 52, CTDB_CONTROL_GET_ALL_TUNABLES = 53, CTDB_CONTROL_KILL_TCP = 54, CTDB_CONTROL_GET_TCP_TICKLE_LIST = 55, CTDB_CONTROL_SET_TCP_TICKLE_LIST = 56, CTDB_CONTROL_REGISTER_SERVER_ID = 57, CTDB_CONTROL_UNREGISTER_SERVER_ID = 58, CTDB_CONTROL_CHECK_SERVER_ID = 59, CTDB_CONTROL_GET_SERVER_ID_LIST = 60, CTDB_CONTROL_DB_ATTACH_PERSISTENT = 61, CTDB_CONTROL_PERSISTENT_STORE = 62, /* obsolete */ CTDB_CONTROL_UPDATE_RECORD = 63, CTDB_CONTROL_SEND_GRATIOUS_ARP = 64, CTDB_CONTROL_TRANSACTION_START = 65, CTDB_CONTROL_TRANSACTION_COMMIT = 66, CTDB_CONTROL_WIPE_DATABASE = 67, /* #68 removed */ CTDB_CONTROL_UPTIME = 69, CTDB_CONTROL_START_RECOVERY = 70, CTDB_CONTROL_END_RECOVERY = 71, CTDB_CONTROL_RELOAD_NODES_FILE = 72, /* #73 removed */ CTDB_CONTROL_TRY_DELETE_RECORDS = 74, CTDB_CONTROL_ENABLE_MONITOR = 75, CTDB_CONTROL_DISABLE_MONITOR = 76, CTDB_CONTROL_ADD_PUBLIC_IP = 77, CTDB_CONTROL_DEL_PUBLIC_IP = 78, CTDB_CONTROL_RUN_EVENTSCRIPTS = 79, CTDB_CONTROL_GET_CAPABILITIES = 80, CTDB_CONTROL_START_PERSISTENT_UPDATE = 81, CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE= 82, CTDB_CONTROL_TRANS2_COMMIT = 83, /* obsolete */ CTDB_CONTROL_TRANS2_FINISHED = 84, /* obsolete */ CTDB_CONTROL_TRANS2_ERROR = 85, /* obsolete */ CTDB_CONTROL_TRANS2_COMMIT_RETRY = 86, /* obsolete */ CTDB_CONTROL_RECD_PING = 87, CTDB_CONTROL_RELEASE_IP = 88, CTDB_CONTROL_TAKEOVER_IP = 89, CTDB_CONTROL_GET_PUBLIC_IPS = 90, CTDB_CONTROL_GET_NODEMAP = 91, CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS = 96, CTDB_CONTROL_TRAVERSE_KILL = 97, CTDB_CONTROL_RECD_RECLOCK_LATENCY = 98, CTDB_CONTROL_GET_RECLOCK_FILE = 99, CTDB_CONTROL_SET_RECLOCK_FILE = 100, CTDB_CONTROL_STOP_NODE = 101, CTDB_CONTROL_CONTINUE_NODE = 102, CTDB_CONTROL_SET_NATGWSTATE = 103, CTDB_CONTROL_SET_LMASTERROLE = 104, CTDB_CONTROL_SET_RECMASTERROLE = 105, CTDB_CONTROL_ENABLE_SCRIPT = 107, CTDB_CONTROL_DISABLE_SCRIPT = 108, CTDB_CONTROL_SET_BAN_STATE = 109, CTDB_CONTROL_GET_BAN_STATE = 110, CTDB_CONTROL_SET_DB_PRIORITY = 111, CTDB_CONTROL_GET_DB_PRIORITY = 112, CTDB_CONTROL_TRANSACTION_CANCEL = 113, CTDB_CONTROL_REGISTER_NOTIFY = 114, CTDB_CONTROL_DEREGISTER_NOTIFY = 115, CTDB_CONTROL_TRANS2_ACTIVE = 116, /* obsolete */ CTDB_CONTROL_GET_LOG = 117, CTDB_CONTROL_CLEAR_LOG = 118, CTDB_CONTROL_TRANS3_COMMIT = 119, CTDB_CONTROL_GET_DB_SEQNUM = 120, CTDB_CONTROL_DB_SET_HEALTHY = 121, CTDB_CONTROL_DB_GET_HEALTH = 122, CTDB_CONTROL_GET_PUBLIC_IP_INFO = 123, CTDB_CONTROL_GET_IFACES = 124, CTDB_CONTROL_SET_IFACE_LINK_STATE = 125, CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE = 126, CTDB_CONTROL_GET_STAT_HISTORY = 127, CTDB_CONTROL_SCHEDULE_FOR_DELETION = 128, CTDB_CONTROL_SET_DB_READONLY = 129, CTDB_CONTROL_CHECK_SRVIDS = 130, CTDB_CONTROL_TRAVERSE_START_EXT = 131, CTDB_CONTROL_GET_DB_STATISTICS = 132, CTDB_CONTROL_SET_DB_STICKY = 133, CTDB_CONTROL_RELOAD_PUBLIC_IPS = 134, CTDB_CONTROL_TRAVERSE_ALL_EXT = 135, CTDB_CONTROL_RECEIVE_RECORDS = 136, CTDB_CONTROL_IPREALLOCATED = 137, CTDB_CONTROL_GET_RUNSTATE = 138, }; /* packet structures */ struct ctdb_req_header { uint32_t length; uint32_t ctdb_magic; uint32_t ctdb_version; uint32_t generation; uint32_t operation; uint32_t destnode; uint32_t srcnode; uint32_t reqid; }; struct ctdb_req_call { struct ctdb_req_header hdr; uint32_t flags; uint32_t db_id; uint32_t callid; uint32_t hopcount; uint32_t keylen; uint32_t calldatalen; uint8_t data[1]; /* key[] followed by calldata[] */ }; struct ctdb_reply_call { struct ctdb_req_header hdr; uint32_t status; uint32_t datalen; uint8_t data[1]; }; struct ctdb_reply_error { struct ctdb_req_header hdr; uint32_t status; uint32_t msglen; uint8_t msg[1]; }; struct ctdb_req_dmaster { struct ctdb_req_header hdr; uint32_t db_id; uint64_t rsn; uint32_t dmaster; uint32_t keylen; uint32_t datalen; uint8_t data[1]; }; struct ctdb_reply_dmaster { struct ctdb_req_header hdr; uint32_t db_id; uint64_t rsn; uint32_t keylen; uint32_t datalen; uint8_t data[1]; }; struct ctdb_req_message { struct ctdb_req_header hdr; uint64_t srvid; uint32_t datalen; uint8_t data[1]; }; struct ctdb_req_getdbpath { struct ctdb_req_header hdr; uint32_t db_id; }; struct ctdb_reply_getdbpath { struct ctdb_req_header hdr; uint32_t datalen; uint8_t data[1]; }; struct ctdb_req_control { struct ctdb_req_header hdr; uint32_t opcode; uint32_t pad; uint64_t srvid; uint32_t client_id; #define CTDB_CTRL_FLAG_NOREPLY 1 #define CTDB_CTRL_FLAG_OPCODE_SPECIFIC 0xFFFF0000 uint32_t flags; uint32_t datalen; uint8_t data[1]; }; struct ctdb_reply_control { struct ctdb_req_header hdr; int32_t status; uint32_t datalen; uint32_t errorlen; uint8_t data[1]; }; struct ctdb_req_keepalive { struct ctdb_req_header hdr; }; /* the extended header for records in the ltdb */ struct ctdb_ltdb_header { uint64_t rsn; uint32_t dmaster; uint32_t reserved1; #define CTDB_REC_FLAG_DEFAULT 0x00000000 #define CTDB_REC_FLAG_MIGRATED_WITH_DATA 0x00010000 #define CTDB_REC_FLAG_VACUUM_MIGRATED 0x00020000 #define CTDB_REC_FLAG_AUTOMATIC 0x00040000 #define CTDB_REC_RO_HAVE_DELEGATIONS 0x01000000 #define CTDB_REC_RO_HAVE_READONLY 0x02000000 #define CTDB_REC_RO_REVOKING_READONLY 0x04000000 #define CTDB_REC_RO_REVOKE_COMPLETE 0x08000000 #define CTDB_REC_RO_FLAGS (CTDB_REC_RO_HAVE_DELEGATIONS|\ CTDB_REC_RO_HAVE_READONLY|\ CTDB_REC_RO_REVOKING_READONLY|\ CTDB_REC_RO_REVOKE_COMPLETE) uint32_t flags; }; /* definitions for different socket structures */ typedef struct sockaddr_in ctdb_addr_in; typedef struct sockaddr_in6 ctdb_addr_in6; typedef union { struct sockaddr sa; ctdb_addr_in ip; ctdb_addr_in6 ip6; } ctdb_sock_addr; /* A structure describing a single node, its flags and its address */ struct ctdb_node_and_flags { uint32_t pnn; uint32_t flags; ctdb_sock_addr addr; }; /* Structure used for a nodemap. The nodemap is the structure containing a list of all nodes known to the cluster and their associated flags. */ struct ctdb_node_map { uint32_t num; struct ctdb_node_and_flags nodes[1]; }; /* * Node flags */ #define NODE_FLAGS_DISCONNECTED 0x00000001 /* node isn't connected */ #define NODE_FLAGS_UNHEALTHY 0x00000002 /* monitoring says node is unhealthy */ #define NODE_FLAGS_PERMANENTLY_DISABLED 0x00000004 /* administrator has disabled node */ #define NODE_FLAGS_BANNED 0x00000008 /* recovery daemon has banned the node */ #define NODE_FLAGS_DELETED 0x00000010 /* this node has been deleted */ #define NODE_FLAGS_STOPPED 0x00000020 /* this node has been stopped */ #define NODE_FLAGS_DISABLED (NODE_FLAGS_UNHEALTHY|NODE_FLAGS_PERMANENTLY_DISABLED) #define NODE_FLAGS_INACTIVE (NODE_FLAGS_DELETED|NODE_FLAGS_DISCONNECTED|NODE_FLAGS_BANNED|NODE_FLAGS_STOPPED) /* * Node capabilities */ #define CTDB_CAP_RECMASTER 0x00000001 #define CTDB_CAP_LMASTER 0x00000002 /* This capability is set if CTDB_LVS_PUBLIC_IP is set */ #define CTDB_CAP_LVS 0x00000004 /* This capability is set if NATGW is enabled */ #define CTDB_CAP_NATGW 0x00000008 struct ctdb_public_ip { uint32_t pnn; ctdb_sock_addr addr; }; struct ctdb_all_public_ips { uint32_t num; struct ctdb_public_ip ips[1]; }; struct latency_counter { int num; double min; double max; double total; }; /* structure used to pass record data between the child and parent */ struct ctdb_rec_data { uint32_t length; uint32_t reqid; uint32_t keylen; uint32_t datalen; uint8_t data[1]; }; struct ctdb_traverse_start { uint32_t db_id; uint32_t reqid; uint64_t srvid; }; struct ctdb_traverse_start_ext { uint32_t db_id; uint32_t reqid; uint64_t srvid; bool withemptyrecords; }; /* ctdb statistics information */ #define MAX_COUNT_BUCKETS 16 #define MAX_HOT_KEYS 10 struct ctdb_statistics { uint32_t num_clients; uint32_t frozen; uint32_t recovering; uint32_t client_packets_sent; uint32_t client_packets_recv; uint32_t node_packets_sent; uint32_t node_packets_recv; uint32_t keepalive_packets_sent; uint32_t keepalive_packets_recv; struct { uint32_t req_call; uint32_t reply_call; uint32_t req_dmaster; uint32_t reply_dmaster; uint32_t reply_error; uint32_t req_message; uint32_t req_control; uint32_t reply_control; } node; struct { uint32_t req_call; uint32_t req_message; uint32_t req_control; } client; struct { uint32_t call; uint32_t control; uint32_t traverse; } timeouts; struct { struct latency_counter ctdbd; struct latency_counter recd; } reclock; struct { uint32_t num_calls; uint32_t num_current; uint32_t num_pending; uint32_t num_failed; struct latency_counter latency; uint32_t buckets[MAX_COUNT_BUCKETS]; } locks; uint32_t total_calls; uint32_t pending_calls; uint32_t childwrite_calls; uint32_t pending_childwrite_calls; uint32_t memory_used; uint32_t __last_counter; /* hack for control_statistics_all */ uint32_t max_hop_count; uint32_t hop_count_bucket[MAX_COUNT_BUCKETS]; struct latency_counter call_latency; struct latency_counter childwrite_latency; uint32_t num_recoveries; struct timeval statistics_start_time; struct timeval statistics_current_time; uint32_t total_ro_delegations; uint32_t total_ro_revokes; }; /* * wire format for statistics history */ struct ctdb_statistics_wire { uint32_t num; struct ctdb_statistics stats[1]; }; /* * db statistics */ struct ctdb_db_statistics { struct { uint32_t num_calls; uint32_t num_current; uint32_t num_pending; uint32_t num_failed; struct latency_counter latency; uint32_t buckets[MAX_COUNT_BUCKETS]; } locks; uint32_t db_ro_delegations; uint32_t db_ro_revokes; uint32_t hop_count_bucket[MAX_COUNT_BUCKETS]; uint32_t num_hot_keys; struct { uint32_t count; TDB_DATA key; } hot_keys[MAX_HOT_KEYS]; char hot_keys_wire[1]; }; /* * wire format for interface list */ #ifdef IFNAMSIZ #define CTDB_IFACE_SIZE IFNAMSIZ #else #define CTDB_IFACE_SIZE 16 #endif struct ctdb_iface_info { char name[CTDB_IFACE_SIZE+2]; uint16_t link_state; uint32_t references; }; struct ctdb_ifaces_list { uint32_t num; struct ctdb_iface_info ifaces[1]; }; #define INVALID_GENERATION 1 /* table that contains the mapping between a hash value and lmaster */ struct ctdb_vnn_map { uint32_t generation; uint32_t size; uint32_t *map; }; /* a wire representation of the vnn map */ struct ctdb_vnn_map_wire { uint32_t generation; uint32_t size; uint32_t map[1]; }; #endif ctdb-2.5.1.dfsg/include/ctdb_version.h0000644000175000017500000000014112245332454017504 0ustar mathieumathieu/* This file is auto-genrated by packaging/mkversion.sh */ #define CTDB_VERSION_STRING "2.5.1" ctdb-2.5.1.dfsg/include/ctdb_client.h0000644000175000017500000005306312245023514017302 0ustar mathieumathieu/* ctdb database library: old client interface Copyright (C) Andrew Tridgell 2006 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #ifndef _CTDB_CLIENT_H #define _CTDB_CLIENT_H #include "ctdb_protocol.h" enum control_state {CTDB_CONTROL_WAIT, CTDB_CONTROL_DONE, CTDB_CONTROL_ERROR, CTDB_CONTROL_TIMEOUT}; struct ctdb_client_control_state { struct ctdb_context *ctdb; uint32_t reqid; int32_t status; TDB_DATA outdata; enum control_state state; char *errormsg; struct ctdb_req_control *c; /* if we have a callback registered for the completion (or failure) of this control if a callback is used, it MUST talloc_free the cb_data passed to it */ struct { void (*fn)(struct ctdb_client_control_state *); void *private_data; } async; }; struct ctdb_client_notify_register { uint64_t srvid; uint32_t len; uint8_t notify_data[1]; }; struct ctdb_client_notify_deregister { uint64_t srvid; }; struct tevent_context; /* initialise ctdb subsystem */ struct ctdb_context *ctdb_init(struct tevent_context *ev); /* choose the transport */ int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport); /* set some flags */ void ctdb_set_flags(struct ctdb_context *ctdb, unsigned flags); /* tell ctdb what address to listen on, in transport specific format */ int ctdb_set_address(struct ctdb_context *ctdb, const char *address); int ctdb_set_socketname(struct ctdb_context *ctdb, const char *socketname); const char *ctdb_get_socketname(struct ctdb_context *ctdb); /* Check that a specific ip address exists in the node list and returns the id for the node or -1 */ int ctdb_ip_to_nodeid(struct ctdb_context *ctdb, const char *nodeip); /* start the ctdb protocol */ int ctdb_start(struct ctdb_context *ctdb); /* attach to a ctdb database */ struct ctdb_db_context *ctdb_attach(struct ctdb_context *ctdb, struct timeval timeout, const char *name, bool persistent, uint32_t tdb_flags); /* find an attached ctdb_db handle given a name */ struct ctdb_db_context *ctdb_db_handle(struct ctdb_context *ctdb, const char *name); /* error string for last ctdb error */ const char *ctdb_errstr(struct ctdb_context *); /* a ctdb call function */ typedef int (*ctdb_fn_t)(struct ctdb_call_info *); /* setup a ctdb call function */ int ctdb_set_call(struct ctdb_db_context *ctdb_db, ctdb_fn_t fn, uint32_t id); /* make a ctdb call. The associated ctdb call function will be called on the DMASTER for the given record */ int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call); /* initiate an ordered ctdb cluster shutdown this function will never return */ void ctdb_shutdown(struct ctdb_context *ctdb); /* return pnn of this node */ uint32_t ctdb_get_pnn(struct ctdb_context *ctdb); /* return the number of nodes */ uint32_t ctdb_get_num_nodes(struct ctdb_context *ctdb); /* setup a handler for ctdb messages */ typedef void (*ctdb_msg_fn_t)(struct ctdb_context *, uint64_t srvid, TDB_DATA data, void *); int ctdb_client_set_message_handler(struct ctdb_context *ctdb, uint64_t srvid, ctdb_msg_fn_t handler, void *private_data); int ctdb_client_remove_message_handler(struct ctdb_context *ctdb, uint64_t srvid, void *private_data); int ctdb_client_check_message_handlers(struct ctdb_context *ctdb, uint64_t *ids, uint32_t num, uint8_t *result); int ctdb_call(struct ctdb_db_context *ctdb_db, struct ctdb_call *call); struct ctdb_client_call_state *ctdb_call_send(struct ctdb_db_context *ctdb_db, struct ctdb_call *call); int ctdb_call_recv(struct ctdb_client_call_state *state, struct ctdb_call *call); /* send a ctdb message */ int ctdb_client_send_message(struct ctdb_context *ctdb, uint32_t pnn, uint64_t srvid, TDB_DATA data); /* Fetch a ctdb record from a remote node . Underneath this will force the dmaster for the record to be moved to the local node. */ struct ctdb_record_handle *ctdb_fetch_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data); struct ctdb_record_handle *ctdb_fetch_readonly_lock(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data, int read_only); int ctdb_record_store(struct ctdb_record_handle *h, TDB_DATA data); int ctdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data); int ctdb_register_message_handler(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, uint64_t srvid, ctdb_msg_fn_t handler, void *private_data); struct ctdb_db_context *find_ctdb_db(struct ctdb_context *ctdb, uint32_t id); struct ctdb_context *ctdb_cmdline_client(struct tevent_context *ev, struct timeval req_timeout); struct ctdb_statistics; int ctdb_ctrl_statistics(struct ctdb_context *ctdb, uint32_t destnode, struct ctdb_statistics *status); int ctdb_ctrl_dbstatistics(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, struct ctdb_db_statistics **dbstat); int ctdb_ctrl_shutdown(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); struct ctdb_vnn_map; int ctdb_ctrl_getvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_vnn_map **vnnmap); int ctdb_ctrl_setvnnmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_vnn_map *vnnmap); /* table that contains a list of all dbids on a node */ struct ctdb_dbid_map { uint32_t num; struct ctdb_dbid { uint32_t dbid; #define CTDB_DB_FLAGS_PERSISTENT 0x01 #define CTDB_DB_FLAGS_READONLY 0x02 #define CTDB_DB_FLAGS_STICKY 0x04 uint8_t flags; } dbs[1]; }; int ctdb_ctrl_getdbmap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_dbid_map **dbmap); struct ctdb_node_map; int ctdb_ctrl_getnodemap(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap); int ctdb_ctrl_getnodemapv4(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_node_map **nodemap); int ctdb_ctrl_reload_nodes_file(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); struct ctdb_key_list { uint32_t dbid; uint32_t num; TDB_DATA *keys; struct ctdb_ltdb_header *headers; TDB_DATA *data; }; int ctdb_ctrl_pulldb( struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout, TDB_DATA *outdata); struct ctdb_client_control_state *ctdb_ctrl_pulldb_send( struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx, struct timeval timeout); int ctdb_ctrl_pulldb_recv( struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, TDB_DATA *outdata); int ctdb_ctrl_pushdb( struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, struct timeval timeout, TDB_DATA indata); struct ctdb_client_control_state *ctdb_ctrl_pushdb_send( struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, struct timeval timeout, TDB_DATA indata); int ctdb_ctrl_pushdb_recv( struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state); int ctdb_ctrl_copydb(struct ctdb_context *ctdb, struct timeval timeout, uint32_t sourcenode, uint32_t destnode, uint32_t dbid, uint32_t lmaster, TALLOC_CTX *mem_ctx); int ctdb_ctrl_getdbpath(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **path); int ctdb_ctrl_getdbname(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **name); int ctdb_ctrl_getdbhealth(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, TALLOC_CTX *mem_ctx, const char **reason); int ctdb_ctrl_getdbseqnum(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t dbid, uint64_t *seqnum); int ctdb_ctrl_createdb(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const char *name, bool persistent); int ctdb_ctrl_process_exists(struct ctdb_context *ctdb, uint32_t destnode, pid_t pid); int ctdb_ctrl_ping(struct ctdb_context *ctdb, uint32_t destnode); int ctdb_ctrl_get_runstate(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *runstate); int ctdb_ctrl_get_config(struct ctdb_context *ctdb); int ctdb_ctrl_get_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t *level); int ctdb_ctrl_set_debuglevel(struct ctdb_context *ctdb, uint32_t destnode, int32_t level); /* change dmaster for all keys in the database to the new value */ int ctdb_ctrl_setdmaster(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, uint32_t dbid, uint32_t dmaster); /* write a record on a specific db (this implicitely updates dmaster of the record to locally be the vnn of the node where the control is executed on) */ int ctdb_ctrl_write_record(struct ctdb_context *ctdb, uint32_t destnode, TALLOC_CTX *mem_ctx, uint32_t dbid, TDB_DATA key, TDB_DATA data); #define CTDB_RECOVERY_NORMAL 0 #define CTDB_RECOVERY_ACTIVE 1 /* get the recovery mode of a remote node */ int ctdb_ctrl_getrecmode(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmode); struct ctdb_client_control_state *ctdb_ctrl_getrecmode_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_getrecmode_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmode); /* set the recovery mode of a remote node */ int ctdb_ctrl_setrecmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmode); /* get the monitoring mode of a remote node */ int ctdb_ctrl_getmonmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *monmode); /* set the monitoring mode of a remote node to active */ int ctdb_ctrl_enable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); /* set the monitoring mode of a remote node to disabled */ int ctdb_ctrl_disable_monmode(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); /* get the recovery master of a remote node */ int ctdb_ctrl_getrecmaster(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t *recmaster); struct ctdb_client_control_state *ctdb_ctrl_getrecmaster_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_getrecmaster_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *recmaster); /* set the recovery master of a remote node */ int ctdb_ctrl_setrecmaster(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmaster); uint32_t *ctdb_get_connected_nodes(struct ctdb_context *ctdb, struct timeval timeout, TALLOC_CTX *mem_ctx, uint32_t *num_nodes); int ctdb_statistics_reset(struct ctdb_context *ctdb, uint32_t destnode); int ctdb_set_logfile(struct ctdb_context *ctdb, const char *logfile, bool use_syslog); typedef int (*ctdb_traverse_func)(struct ctdb_context *, TDB_DATA, TDB_DATA, void *); int ctdb_traverse(struct ctdb_db_context *ctdb_db, ctdb_traverse_func fn, void *private_data); struct ctdb_dump_db_context { FILE *f; bool printemptyrecords; bool printdatasize; bool printlmaster; bool printhash; bool printrecordflags; }; int ctdb_dumpdb_record(struct ctdb_context *ctdb, TDB_DATA key, TDB_DATA data, void *p); int ctdb_dump_db(struct ctdb_db_context *ctdb_db, struct ctdb_dump_db_context *ctx); /* get the pid of a ctdb daemon */ int ctdb_ctrl_getpid(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *pid); int ctdb_ctrl_freeze(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_freeze_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t priority); struct ctdb_client_control_state * ctdb_ctrl_freeze_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, uint32_t priority); int ctdb_ctrl_freeze_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state); int ctdb_ctrl_thaw_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t priority); int ctdb_ctrl_thaw(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_getpnn(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_get_tunable(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *name, uint32_t *value); int ctdb_ctrl_set_tunable(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *name, uint32_t value); int ctdb_ctrl_list_tunables(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const char ***list, uint32_t *count); int ctdb_ctrl_modflags(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t set, uint32_t clear); enum ctdb_server_id_type { SERVER_TYPE_SAMBA=1, SERVER_TYPE_NFSD=2, SERVER_TYPE_ISCSID=3 }; struct ctdb_server_id { enum ctdb_server_id_type type; uint32_t pnn; uint32_t server_id; }; struct ctdb_server_id_list { uint32_t num; struct ctdb_server_id server_ids[1]; }; int ctdb_ctrl_register_server_id(struct ctdb_context *ctdb, struct timeval timeout, struct ctdb_server_id *id); int ctdb_ctrl_unregister_server_id(struct ctdb_context *ctdb, struct timeval timeout, struct ctdb_server_id *id); int ctdb_ctrl_check_server_id(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_server_id *id, uint32_t *status); int ctdb_ctrl_get_server_id_list(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_server_id_list **svid_list); struct ctdb_uptime { struct timeval current_time; struct timeval ctdbd_start_time; struct timeval last_recovery_started; struct timeval last_recovery_finished; }; /* struct for tcp_client control this is an ipv4 only version of this structure used by samba samba will later be migrated over to use the ctdb_control_tcp_addr structure instead */ struct ctdb_control_tcp { struct sockaddr_in src; /* samba uses this */ struct sockaddr_in dest; /* samba uses this */ }; /* new style structure */ struct ctdb_control_tcp_addr { ctdb_sock_addr src; ctdb_sock_addr dest; }; int ctdb_socket_connect(struct ctdb_context *ctdb); /* get the uptime of a remote node */ int ctdb_ctrl_uptime(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_uptime **uptime); struct ctdb_client_control_state *ctdb_ctrl_uptime_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_uptime_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, struct ctdb_uptime **uptime); int ctdb_ctrl_end_recovery(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_getreclock(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, const char **reclock); int ctdb_ctrl_setreclock(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *reclock); uint32_t *list_of_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *node_map, TALLOC_CTX *mem_ctx, uint32_t mask, int exclude_pnn); uint32_t *list_of_connected_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *node_map, TALLOC_CTX *mem_ctx, bool include_self); uint32_t *list_of_active_nodes(struct ctdb_context *ctdb, struct ctdb_node_map *node_map, TALLOC_CTX *mem_ctx, bool include_self); uint32_t *list_of_vnnmap_nodes(struct ctdb_context *ctdb, struct ctdb_vnn_map *vnn_map, TALLOC_CTX *mem_ctx, bool include_self); int ctdb_read_pnn_lock(int fd, int32_t pnn); /* get capabilities of a remote node */ int ctdb_ctrl_getcapabilities(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t *capabilities); struct ctdb_client_control_state *ctdb_ctrl_getcapabilities_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_getcapabilities_recv(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ctdb_client_control_state *state, uint32_t *capabilities); struct ctdb_marshall_buffer *ctdb_marshall_add(TALLOC_CTX *mem_ctx, struct ctdb_marshall_buffer *m, uint64_t db_id, uint32_t reqid, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data); TDB_DATA ctdb_marshall_finish(struct ctdb_marshall_buffer *m); struct ctdb_transaction_handle *ctdb_transaction_start(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx); int ctdb_transaction_fetch(struct ctdb_transaction_handle *h, TALLOC_CTX *mem_ctx, TDB_DATA key, TDB_DATA *data); int ctdb_transaction_store(struct ctdb_transaction_handle *h, TDB_DATA key, TDB_DATA data); int ctdb_transaction_commit(struct ctdb_transaction_handle *h); int ctdb_transaction_cancel(struct ctdb_transaction_handle *h); int ctdb_ctrl_recd_ping(struct ctdb_context *ctdb); int switch_from_server_to_client(struct ctdb_context *ctdb, const char *fmt, ...); int ctdb_ctrl_getscriptstatus(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, enum ctdb_eventscript_call type, struct ctdb_scripts_wire **script_status); struct debug_levels { int32_t level; const char *description; }; extern struct debug_levels debug_levels[]; const char *get_debug_by_level(int32_t level); int32_t get_debug_by_desc(const char *desc); int ctdb_ctrl_stop_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_continue_node(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode); int ctdb_ctrl_setnatgwstate(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t natgwstate); int ctdb_ctrl_setlmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t lmasterrole); int ctdb_ctrl_setrecmasterrole(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t recmasterrole); int ctdb_ctrl_enablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script); int ctdb_ctrl_disablescript(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, const char *script); struct ctdb_ban_time { uint32_t pnn; uint32_t time; }; int ctdb_ctrl_set_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_ban_time *bantime); int ctdb_ctrl_get_ban(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_ban_time **bantime); struct ctdb_db_priority { uint32_t db_id; uint32_t priority; }; int ctdb_ctrl_set_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, struct ctdb_db_priority *db_prio); int ctdb_ctrl_get_db_priority(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, uint32_t db_id, uint32_t *priority); int ctdb_ctrl_getstathistory(struct ctdb_context *ctdb, struct timeval timeout, uint32_t destnode, TALLOC_CTX *mem_ctx, struct ctdb_statistics_wire **stats); struct ctdb_client_control_state * ctdb_ctrl_updaterecord_send(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data); int ctdb_ctrl_updaterecord_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state); int ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data); struct ctdb_client_control_state * ctdb_ctrl_set_db_readonly_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid); int ctdb_ctrl_set_db_readonly_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state); int ctdb_ctrl_set_db_readonly(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid); struct ctdb_client_control_state * ctdb_ctrl_set_db_sticky_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid); int ctdb_ctrl_set_db_sticky_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state); int ctdb_ctrl_set_db_sticky(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid); #endif /* _CTDB_CLIENT_H */ ctdb-2.5.1.dfsg/include/cmdline.h0000644000175000017500000000035412245023514016436 0ustar mathieumathieu extern struct poptOption popt_ctdb_cmdline[]; #define POPT_CTDB_CMDLINE { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_ctdb_cmdline, 0, "Common ctdb test options:", NULL }, struct ctdb_context *ctdb_cmdline_init(struct event_context *ev); ctdb-2.5.1.dfsg/config/0000755000175000017500000000000012245023514014472 5ustar mathieumathieuctdb-2.5.1.dfsg/config/README0000644000175000017500000000147012245023514015354 0ustar mathieumathieuThis directory contains run-time support scripts for CTDB. Selected highlights: ctdb.init An initscript for starting ctdbd at boot time. events.d/ Eventscripts. See events.d/README for more details. functions Support functions, sourced by eventscripts and other scripts. statd-callout rpc.statd high-availability callout to support lock migration on failover. Notes: * All of these scripts are written in POSIX Bourne shell. Please avoid bash-isms, including the use of "local" variables (which are not available in POSIX shell). * Do not use absolute paths for commands. Unit tests attempt to replace many commands with stubs and can not do this if commands are specified with absolute paths. The functions file controls $PATH so absolute paths should not be required. ctdb-2.5.1.dfsg/config/ctdb.init0000755000175000017500000000710012245023514016274 0ustar mathieumathieu#!/bin/sh # Start and stop CTDB (Clustered TDB daemon) # # chkconfig: - 90 01 # # description: Starts and stops CTDB # pidfile: /var/run/ctdb/ctdbd.pid # config: /etc/sysconfig/ctdb ### BEGIN INIT INFO # Provides: ctdb # Required-Start: $local_fs $syslog $network $remote_fs # Required-Stop: $local_fs $syslog $network $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: start and stop ctdb service # Description: Start and stop CTDB (Clustered TDB daemon) ### END INIT INFO # Source function library. if [ -f /etc/init.d/functions ] ; then # Red Hat . /etc/init.d/functions elif [ -f /etc/rc.d/init.d/functions ] ; then # Red Hat . /etc/rc.d/init.d/functions elif [ -f /etc/rc.status ] ; then # SUSE . /etc/rc.status rc_reset LC_ALL=en_US.UTF-8 elif [ -f /lib/lsb/init-functions ] ; then # Debian . /lib/lsb/init-functions fi # Avoid using root's TMPDIR unset TMPDIR [ -n "$CTDB_BASE" ] || export CTDB_BASE="/etc/ctdb" . "${CTDB_BASE}/functions" loadconfig "network" loadconfig "ctdb" # check networking is up (for redhat) if [ "$NETWORKING" = "no" ] ; then exit 0 fi detect_init_style export CTDB_INIT_STYLE ctdbd="${CTDBD:-/usr/sbin/ctdbd}" ctdbd_wrapper="${CTDBD_WRAPPER:-/usr/sbin/ctdbd_wrapper}" pidfile="${CTDB_PIDFILE:-/var/run/ctdb/ctdbd.pid}" ############################################################ start() { echo -n "Starting ctdbd service: " case "$CTDB_INIT_STYLE" in suse) startproc \ "$ctdbd_wrapper" "$pidfile" "start" rc_status -v ;; redhat) daemon --pidfile "$pidfile" \ "$ctdbd_wrapper" "$pidfile" "start" RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ctdb || RETVAL=1 return $RETVAL ;; debian) eval start-stop-daemon --start --quiet --background --exec \ "$ctdbd_wrapper" "$pidfile" "start" ;; esac } stop() { echo -n "Shutting down ctdbd service: " case "$CTDB_INIT_STYLE" in suse) "$ctdbd_wrapper" "$pidfile" "stop" rc_status -v ;; redhat) "$ctdbd_wrapper" "$pidfile" "stop" RETVAL=$? [ $RETVAL -eq 0 ] && success || failure echo "" [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ctdb return $RETVAL ;; debian) "$ctdbd_wrapper" "$pidfile" "stop" log_end_msg $? ;; esac } restart() { stop start } check_status () { # Backward compatibility. When we arrange to pass --pidfile to # ctdbd we also create the directory that will contain it. If # that directory is missing then we don't use the pidfile to check # status. Note that this probably won't work if # $CTDB_VALGRIND="yes" but this doesn't need full backward # compatibility because it is a debug option. if [ -d $(dirname "$pidfile") ] ; then _pf_opt="-p $pidfile" else _pf_opt="" fi case "$CTDB_INIT_STYLE" in suse) checkproc $_pf_opt "$ctdbd" rc_status -v ;; redhat) status $_pf_opt -l "ctdb" "$ctdbd" ;; debian) status_of_proc $_pf_opt "$ctdbd" "ctdb" ;; esac } ############################################################ case "$1" in start) start ;; stop) stop ;; restart|reload|force-reload) restart ;; status) check_status ;; condrestart|try-restart) if check_status >/dev/null ; then restart fi ;; cron) # used from cron to auto-restart ctdb check_status >/dev/null 2>&1 || restart ;; *) echo "Usage: $0 {start|stop|restart|reload|force-reload|status|cron|condrestart|try-restart}" exit 1 esac ctdb-2.5.1.dfsg/config/ctdbd_wrapper0000755000175000017500000001675112245023514017252 0ustar mathieumathieu#!/bin/sh # ctdbd wrapper - start or stop CTDB usage () { echo "usage: ctdbd_wrapper { start | stop }" exit 1 } [ $# -eq 2 ] || usage pidfile="$1" action="$2" ############################################################ [ -n "$CTDB_BASE" ] || export CTDB_BASE="/etc/ctdb" . "${CTDB_BASE}/functions" loadconfig "ctdb" export CTDB_SOCKET ctdbd="${CTDBD:-/usr/sbin/ctdbd}" ############################################################ # ctdbd_is_running() # 1. Check if ctdbd is running. # - If the PID file is being used then, if the PID file is present, # ctdbd is only considered to running if the PID in the file is # active. # - If the PID file is not being used (i.e. we're upgrading from a # version that doesn't support it) then the presence of any ctdbd # processes is enough proof. # 2. Print a comma-separated list of PIDs that can be # used with "pkill -s". # - If the PID file is being used then this is just the PID in that # file. This also happens to be the session ID, so can be used # to kill all CTDB processes. # - If the PID file is not being used (i.e. upgrading) then this is # just any ctdbd processes that are running. Hopefully one of # them is the session ID so that it can be used to kill all CTDB # processes. # Combining these 2 checks is an optimisation to avoid potentially # running too many pgrep/pkill processes on an already loaded system. # Trawling through /proc/ can be very expensive. ctdbd_is_running () { # If the directory for the PID file exists then respect the # existence of a PID file. _pidfile_dir=$(dirname "$pidfile") if [ -d "$_pidfile_dir" ] ; then if read _pid 2>/dev/null <"$pidfile" ; then echo "$_pid" # Return value of kill is used kill -0 $_pid 2>/dev/null else # Missing/empty PID file return 1 fi else if _pid=$(pgrep -f "${ctdbd}\>") ; then echo $_pid | sed -e 's@ @,@g' return 0 else return 1 fi fi } ############################################################ build_ctdb_options () { ctdb_options="" maybe_set () { # If the given variable isn't set then do nothing [ -n "$2" ] || return # If a required value for the variable and it doesn't match, # then do nothing [ -z "$3" -o "$3" = "$2" ] || return val="'$2'" case "$1" in --*) sep="=" ;; -*) sep=" " ;; esac # For these options we're only passing a value-less flag. if [ -n "$3" ] ; then val="" sep="" fi ctdb_options="${ctdb_options}${ctdb_options:+ }${1}${sep}${val}" } if [ -z "$CTDB_RECOVERY_LOCK" ] ; then echo "No recovery lock specified. Starting CTDB without split brain preventivon" fi maybe_set "--reclock" "$CTDB_RECOVERY_LOCK" maybe_set "--pidfile" "$pidfile" # build up ctdb_options variable from optional parameters maybe_set "--logfile" "$CTDB_LOGFILE" maybe_set "--nlist" "$CTDB_NODES" maybe_set "--socket" "$CTDB_SOCKET" maybe_set "--public-addresses" "$CTDB_PUBLIC_ADDRESSES" maybe_set "--public-interface" "$CTDB_PUBLIC_INTERFACE" maybe_set "--dbdir" "$CTDB_DBDIR" maybe_set "--dbdir-persistent" "$CTDB_DBDIR_PERSISTENT" maybe_set "--dbdir-state" "$CTDB_DBDIR_STATE" maybe_set "--event-script-dir" "$CTDB_EVENT_SCRIPT_DIR" maybe_set "--transport" "$CTDB_TRANSPORT" maybe_set "-d" "$CTDB_DEBUGLEVEL" maybe_set "--notification-script" "$CTDB_NOTIFY_SCRIPT" maybe_set "--start-as-disabled" "$CTDB_START_AS_DISABLED" "yes" maybe_set "--start-as-stopped " "$CTDB_START_AS_STOPPED" "yes" maybe_set "--no-recmaster" "$CTDB_CAPABILITY_RECMASTER" "no" maybe_set "--no-lmaster" "$CTDB_CAPABILITY_LMASTER" "no" maybe_set "--lvs --single-public-ip" "$CTDB_LVS_PUBLIC_IP" maybe_set "--script-log-level" "$CTDB_SCRIPT_LOG_LEVEL" maybe_set "--log-ringbuf-size" "$CTDB_LOG_RINGBUF_SIZE" maybe_set "--syslog" "$CTDB_SYSLOG" "yes" maybe_set "--max-persistent-check-errors" "$CTDB_MAX_PERSISTENT_CHECK_ERRORS" } export_debug_variables () { export CTDB_DEBUG_HUNG_SCRIPT CTDB_EXTERNAL_TRACE CTDB_DEBUG_LOCKS } kill_ctdbd () { _session="$1" if [ -n "$_session" ] ; then pkill -9 -s "$_session" 2>/dev/null fi rm -f "$pidfile" } ############################################################ start() { if _session=$(ctdbd_is_running) ; then echo $"CTDB is already running" return 0 fi # About to start new $ctdbd. The main daemon is not running but # there may still be other processes around, so do some cleanup. # Note that starting ctdbd below will destroy the Unix domain # socket, so any processes that aren't yet completely useless soon # will be, so this can really do no harm. kill_ctdbd "$_session" build_ctdb_options export_debug_variables if [ "$CTDB_SUPPRESS_COREFILE" = "yes" ]; then ulimit -c 0 else ulimit -c unlimited fi mkdir -p $(dirname "$pidfile") if [ -n "$CTDB_VALGRIND" -a "$CTDB_VALGRIND" != "no" ] ; then if [ "$CTDB_VALGRIND" = "yes" ] ; then ctdbd="valgrind -q --log-file=/var/log/ctdb_valgrind ${ctdbd}" else ctdbd="${CTDB_VALGRIND} ${ctdbd}" fi ctdb_options="${ctdb_options} --valgrinding" fi if [ "$CTDB_SYSLOG" != "yes" ] ; then logger -t ctdbd "CTDB is being run without syslog enabled. Logs will be in ${CTDB_LOGFILE:-/var/log/log.ctdb}" fi eval "$ctdbd" "$ctdb_options" || return 1 # Wait until ctdbd has started and is ready to respond to clients. _pid="" _timeout="${CTDB_STARTUP_TIMEOUT:-10}" _count=0 while [ $_count -lt $_timeout ] ; do # If we don't have the PID then try to read it. [ -n "$_pid" ] || read _pid 2>/dev/null <"$pidfile" # If we got the PID but the PID file has gone or the process # is no longer running then stop waiting... CTDB is dead. if [ -n "$_pid" ] ; then if [ ! -e "$pidfile" ] || ! kill -0 "$_pid" 2>/dev/null ; then echo "CTDB exited during initialisation - check logs." kill_ctdbd "$_pid" drop_all_public_ips >/dev/null 2>&1 return 1 fi if ctdb runstate first_recovery startup running >/dev/null 2>&1 ; then return 0 fi fi _count=$(($_count + 1)) sleep 1 done echo "Timed out waiting for initialisation - check logs - killing CTDB" kill_ctdbd "$_pid" drop_all_public_ips >/dev/null 2>&1 return 1 } stop() { if ! _session=$(ctdbd_is_running) ; then echo "CTDB is not running" return 0 fi ctdb shutdown # Wait for remaining CTDB processes to exit... _timeout=${CTDB_SHUTDOWN_TIMEOUT:-30} _count=0 while [ $_count -lt $_timeout ] ; do pkill -0 -s "$_session" 2>/dev/null || return 0 _count=$(($_count + 1)) sleep 1 done echo "Timed out waiting for CTDB to shutdown. Killing CTDB processes." kill_ctdbd "$_session" drop_all_public_ips >/dev/null 2>&1 sleep 1 if pkill -0 -s "$_session" ; then # If SIGKILL didn't work then things are bad... echo "Failed to kill all CTDB processes. Giving up." return 1 fi return 0 } ############################################################ # Allow notifications for start/stop. if [ -x "$CTDB_BASE/rc.ctdb" ] ; then "$CTDB_BASE/rc.ctdb" "$action" fi case "$action" in start) start ;; stop) stop ;; *) echo "usage: $0 {start|stop}" exit 1 esac ctdb-2.5.1.dfsg/config/notify.sh0000755000175000017500000000102212245023514016334 0ustar mathieumathieu#!/bin/sh # This script is activated by setting CTDB_NOTIFY_SCRIPT=/etc/ctdb/notify.sh # in /etc/sysconfig/ctdb # This is script is invoked from ctdb when certain events happen. See # /etc/ctdb/notify.d/README for more details. d=$(dirname $0) nd="${d}/notify.d" ok=true for i in "${nd}/"* ; do # Don't run files matching basename case "${i##*/}" in *~|*,|*.rpm*|*.swp|README) continue ;; esac # Files must be executable [ -x "$i" ] || continue # Flag failures "$i" "$1" || ok=false done $ok ctdb-2.5.1.dfsg/config/notify.d.README0000755000175000017500000000237612245023514017116 0ustar mathieumathieuThis directory should contain executable programs to handle CTDB event notifications. The first and only argument passed to each program is the event, which is one of: init, setup, startup, unhealthy, healthy To use notifications with this directory then you need to set: CTDB_NOTIFY_SCRIPT=/etc/ctdb/notify.sh in your CTDB configuration file. An example script that sends SNMP traps for unhealthy/healthy might look like this: #!/bin/sh case "$1" in unhealthy) # Send an SNMP trap saying that the node is unhealthy: snmptrap -m ALL -v 1 -c public 10.1.1.105 ctdb \ $(hostname) 0 0 $(date +"%s") ctdb.nodeHealth.0 i 1 ;; healthy) # Send an SNMP trap saying that the node is healthy again: snmptrap -m ALL -v 1 -c public 10.1.1.105 ctdb \ $(hostname) 0 0 $(date +"%s") ctdb.nodeHealth.0 i 0 ;; esac Alternatively, email could be sent: #!/bin/sh case "$1" in unhealthy) mail -s "$(hostname) is UNHEALTHY" foo@example.com /dev/null 2>&1 ;; healthy) mail -s "$(hostname) is HEALTHY" foo@example.com /dev/null 2>&1 ;; esac When adding programs please note the exclusion patterns in notify.sh. ctdb-2.5.1.dfsg/config/ctdb.service0000644000175000017500000000046212245023514016772 0ustar mathieumathieu[Unit] Description=CTDB After=network.target [Service] Type=forking LimitCORE=infinity PIDFile=/run/ctdb/ctdbd.pid ExecStart=/usr/sbin/ctdbd_wrapper /run/ctdb/ctdbd.pid start ExecStop=/usr/sbin/ctdbd_wrapper /run/ctdb/ctdbd.pid stop KillMode=control-group Restart=no [Install] WantedBy=multi-user.target ctdb-2.5.1.dfsg/config/nfs-rpc-checks.d/0000755000175000017500000000000012245023514017522 5ustar mathieumathieuctdb-2.5.1.dfsg/config/nfs-rpc-checks.d/10.statd.check0000644000175000017500000000007612245023514022062 0ustar mathieumathieu-ge 6 verbose unhealthy -eq 4 verbose restart -eq 2 restart:b ctdb-2.5.1.dfsg/config/nfs-rpc-checks.d/30.lockd.check0000644000175000017500000000006412245023514022036 0ustar mathieumathieu-ge 15 verbose restart:b unhealthy -eq 10 restart:b ctdb-2.5.1.dfsg/config/nfs-rpc-checks.d/40.mountd.check0000644000175000017500000000006312245023514022250 0ustar mathieumathieu-ge 10 verbose restart:b unhealthy -eq 5 restart:b ctdb-2.5.1.dfsg/config/nfs-rpc-checks.d/50.rquotad.check0000644000175000017500000000003012245023514022414 0ustar mathieumathieu-gt 0 verbose restart:b ctdb-2.5.1.dfsg/config/nfs-rpc-checks.d/20.nfsd.check0000644000175000017500000000007412245023514021674 0ustar mathieumathieu% 10 verbose restart:b unhealthy -ge 2 verbose unhealthy ctdb-2.5.1.dfsg/config/statd-callout0000755000175000017500000001503612245023514017205 0ustar mathieumathieu#!/bin/sh # This must run as root as CTDB tool commands need to access CTDB socket [ $(id -u) -eq 0 ] || exec sudo "$0" "$@" # this script needs to be installed so that statd points to it with the -H # command line argument. The easiest way to do that is to put something like this in # /etc/sysconfig/nfs: # STATD_HOSTNAME="myhostname -H /etc/ctdb/statd-callout" [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; echo "$PWD") . $CTDB_BASE/functions # Overwrite this so we get some logging die () { script_log "statd-callout" "$@" exit 1 } loadconfig ctdb loadconfig nfs [ -n "$NFS_HOSTNAME" ] || \ die "NFS_HOSTNAME is not configured. statd-callout failed" # A handy newline nl=" " case "$1" in add-client) # statd does not tell us to which IP the client connected so # we must add it to all the IPs that we serve cip="$2" pnn=$(ctdb xpnn | sed -e 's/.*://') date=$(date '+%s') ctdb ip -Y | tail -n +2 | { # This all needs to be in the end of the pipe so it # doesn't get lost items="" while IFS=":" read x sip node x ; do [ "$node" = "$pnn" ] || continue # not us key="statd-state@${sip}@${cip}" item="\"${key}\" \"${date}\"" items="${items}${items:+${nl}}${item}" done if ! echo "$items" | ctdb ptrans "ctdb.tdb" ; then die "Failed to add clients" fi } ;; del-client) # statd does not tell us from which IP the client disconnected # so we must add it to all the IPs that we serve cip="$2" pnn=$(ctdb xpnn | sed -e 's/.*://') ctdb ip -Y | tail -n +2 | { # This all needs to be in the end of the pipe so it # doesn't get lost items="" while IFS=":" read x sip node x ; do [ "$node" = "$pnn" ] || continue # not us key="statd-state@${sip}@${cip}" item="\"${key}\" \"\"" items="${items}${items:+${nl}}${item}" done if ! echo "$items" | ctdb ptrans "ctdb.tdb" ; then die "Failed to delete clients" fi } ;; notify) # we must restart the lockmanager (on all nodes) so that we get # a clusterwide grace period (so other clients dont take out # conflicting locks through other nodes before all locks have been # reclaimed) # we need these settings to make sure that no tcp connections survive # across a very fast failover/failback #echo 10 > /proc/sys/net/ipv4/tcp_fin_timeout #echo 0 > /proc/sys/net/ipv4/tcp_max_tw_buckets #echo 0 > /proc/sys/net/ipv4/tcp_max_orphans # Delete the notification list for statd, we dont want it to # ping any clients rm -f /var/lib/nfs/statd/sm/* rm -f /var/lib/nfs/statd/sm.bak/* # we must keep a monotonically increasing state variable for the entire # cluster so state always increases when ip addresses fail from one # node to another # We use epoch and hope the nodes are close enough in clock. # Even numbers mean service is shut down, odd numbers mean # service is started. state_even=$(( $(date '+%s') / 2 * 2)) # we must also let some time pass between stopping and restarting the # lockmanager since othervise there is a window where the lockmanager # will respond "strangely" immediately after restarting it, which # causes clients to fail to reclaim the locks. # if [ "${CTDB_NFS_SERVER_MODE:-${NFS_SERVER_MODE}}" != "ganesha" ] ; then startstop_nfslock stop >/dev/null 2>&1 sleep 2 startstop_nfslock start >/dev/null 2>&1 fi # we now need to send out additional statd notifications to ensure # that clients understand that the lockmanager has restarted. # we have three cases: # 1, clients that ignore the ip address the stat notification came from # and ONLY care about the 'name' in the notify packet. # these clients ONLY work with lock failover IFF that name # can be resolved into an ipaddress that matches the one used # to mount the share. (==linux clients) # This is handled when starting lockmanager above, but those # packets are sent from the "wrong" ip address, something linux # clients are ok with, buth other clients will barf at. # 2, Some clients only accept statd packets IFF they come from the # 'correct' ip address. # 2a,Send out the notification using the 'correct' ip address and also # specify the 'correct' hostname in the statd packet. # Some clients require both the correct source address and also the # correct name. (these clients also ONLY work if the ip addresses # used to map the share can be resolved into the name returned in # the notify packet.) # 2b,Other clients require that the source ip address of the notify # packet matches the ip address used to take out the lock. # I.e. that the correct source address is used. # These clients also require that the statd notify packet contains # the name as the ip address used when the lock was taken out. # # Both 2a and 2b are commonly used in lockmanagers since they maximize # probability that the client will accept the statd notify packet and # not just ignore it. # For all IPs we serve, collect info and push to the config database pnn=$(ctdb xpnn | sed -e 's/.*://') # Construct a sed expression to take catdb output and produce pairs of: # server-IP client-IP # but only for the server-IPs that are hosted on this node. sed_expr=$(ctdb ip | tail -n +2 | awk -v pnn=$pnn 'pnn == $2 { printf "s/^key.*=.*statd-state@\\(%s\\)@\\([^\"]*\\).*/\\1 \\2/p\n", gensub(/\./, "\\\\.", "g", $1) }') statd_state=$(ctdb catdb ctdb.tdb | sed -n "$sed_expr" | sort) [ -n "$statd_state" ] || exit 0 # The following is dangerous if this script times out before # all of the smnotify commands are run. Revert to individual # pdelete commands for now and consider optimising smnotify to # read all the data from stdin and then run it in the # background. # # Delete all the items from the TDB #if ! echo "$statd_state" | \ # awk '{ printf "\"statd-state@%s@%s\" \"\"\n", $1, $2 }') | \ # ctdb ptrans ctdb.tdb ; then # die "Yikes!" #fi prev="" echo "$statd_state" | while read sip cip ; do # Delete the entry from the DB ctdb pdelete ctdb.tdb "statd-state@${sip}@${cip}" # Reset stateval for each serverip [ "$sip" = "$prev" ] || stateval="$state_even" # Send notifies for server shutdown smnotify --client=$cip --ip=$sip --server=$sip --stateval=$stateval smnotify --client=$cip --ip=$sip --server=$NFS_HOSTNAME --stateval=$stateval # Send notifies for server startup stateval=$(($stateval + 1)) smnotify --client=$cip --ip=$sip --server=$sip --stateval=$stateval smnotify --client=$cip --ip=$sip --server=$NFS_HOSTNAME --stateval=$stateval done ;; esac ctdb-2.5.1.dfsg/config/debug-hung-script.sh0000755000175000017500000000114012245023514020354 0ustar mathieumathieu#!/bin/sh ( flock --wait 2 9 || exit 1 echo "===== Start of hung script debug for PID=\"$1\", event=\"$2\" =====" echo "pstree -p -a ${1}:" pstree -p -a $1 if [ "$2" = "init" ] ; then exit 0 fi echo "ctdb scriptstatus ${2}:" # No use running several of these in parallel if, say, "releaseip" # event hangs for multiple IPs. In that case the output would be # interleaved in the log and would just be confusing. ctdb scriptstatus "$2" echo "===== End of hung script debug for PID=\"$1\", event=\"$2\" =====" ) 9>"${CTDB_VARDIR}/debug-hung-script.lock" ctdb-2.5.1.dfsg/config/gcore_trace.sh0000755000175000017500000000011512245023514017303 0ustar mathieumathieu#!/bin/sh gcore -o "/var/log/core" "$1" 2>&1 | logger -t "ctdb:gcore_trace" ctdb-2.5.1.dfsg/config/events.d/0000755000175000017500000000000012245023514016220 5ustar mathieumathieuctdb-2.5.1.dfsg/config/events.d/README0000644000175000017500000001460112245023514017102 0ustar mathieumathieuThis directory is where you should put any local or application specific event scripts for ctdb to call. All event scripts start with the prefic 'NN.' where N is a digit. The event scripts are run in sequence based on NN. Thus 10.interfaces will be run before 60.nfs. Each NN must be unique and duplicates will cause undefined behaviour. I.e. having both 10.interfaces and 10.otherstuff is not allowed. As a special case, any eventscript that ends with a '~' character will be ignored since this is a common postfix that some editors will append to older versions of a file. Only event scripts with executable permissions are run from CTDB. Any event script that does not have executable permission is ignored. The eventscripts are called with varying number of arguments. The first argument is the "event" and the rest of the arguments depend on which event was triggered. All of the events except the 'shutdown' and 'startrecovery' events will be called with the ctdb daemon in NORMAL mode (ie. not in recovery) The events currently implemented are init This event does not take any additional arguments. This event is only invoked once, when ctdb is starting up. This event is used to do some cleanup work from earlier runs and prepare the basic setup. At this stage 'ctdb' commands won't work. Example: 00.ctdb cleans up $CTDB_VARDIR/state setup This event does not take any additional arguments. This event is only invoked once, after init event is completed. This event is used to do setup any tunables defined in ctdb configuration file. startup This event does not take any additional arguments. This event is only invoked once, when ctdb has finished the initial recoveries. This event is used to wait for the service to start and all resources for the service becoming available. This is used to prevent ctdb from starting up and advertize its services until all dependent services have become available. All services that are managed by ctdb should implement this event and use it to start the service. Example: 50.samba uses this event to start the samba daemon and then wait until samba and all its associated services have become available. It then also proceeds to wait until all shares have become available. shutdown This event is called when the ctdb service is shuting down. All services that are managed by ctdb should implement this event and use it to perform a controlled shutdown of the service. Example: 60.nfs uses this event to shut down nfs and all associated services and stop exporting any shares when this event is invoked. monitor This event is invoked every X number of seconds. The interval can be configured using the MonitorInterval tunable but defaults to 15 seconds. This event is triggered by ctdb to continuously monitor that all managed services are healthy. When invoked, the event script will check that the service is healthy and return 0 if so. If the service is not healthy the event script should return non zero. If a service returns nonzero from this script this will cause ctdb to consider the node status as UNHEALTHY and will cause the public address and all associated services to be failed over to a different node in the cluster. All managed services should implement this event. Example: 10.interfaces which checks that the public interface (if used) is healthy, i.e. it has a physical link established. takeip This event is triggered everytime the node takes over a public ip address during recovery. This event takes three additional arguments : 'interface' 'ipaddress' and 'netmask' Before this event there will always be a 'startrecovery' event. This event will always be followed by a 'recovered' event once all ipaddresses have been reassigned to new nodes and the ctdb database has been recovered. If multiple ip addresses are reassigned during recovery it is possible to get several 'takeip' events followed by a single 'recovered' event. Since there might involve substantial work for the service when an ip address is taken over and since multiple ip addresses might be taken over in a single recovery it is often best to only mark which addresses are being taken over in this event and defer the actual work to reconfigure or restart the services until the 'recovered' event. Example: 60.nfs which just records which ip addresses are being taken over into a local state directory and which defers the actual restart of the services until the 'recovered' event. releaseip This event is triggered everytime the node releases a public ip address during recovery. This event takes three additional arguments : 'interface' 'ipaddress' and 'netmask' In all other regards this event is analog to the 'takeip' event above. Example: 60.nfs updateip This event is triggered everytime the node moves a public ip address between interfaces This event takes four additional arguments : 'old-interface' 'new-interface' 'ipaddress' and 'netmask' Example: 10.interface startrecovery This event is triggered everytime we start a recovery process or before we start changing ip address allocations. recovered This event is triggered every time we have finished a full recovery and also after we have finished reallocating the public ip addresses across the cluster. Example: 60.nfs which if the ip address configuration has changed during the recovery (i.e. if addresses have been taken over or released) will kill off any tcp connections that exist for that service and also send out statd notifications to all registered clients. ipreallocated This event is triggered after releaseip and takeip events in a takeover run. It can be used to reconfigure services, update routing and many other things. Additional note for takeip, releaseip, recovered: ALL services that depend on the ip address configuration of the node must implement all three of these events. ALL services that use TCP should also implement these events and at least kill off any tcp connections to the service if the ip address config has changed in a similar fashion to how 60.nfs does it. The reason one must do this is that ESTABLISHED tcp connections may survive when an ip address is released and removed from the host until the ip address is re-takenover. Any tcp connections that survive a release/takeip sequence can potentially cause the client/server tcp connection to get out of sync with sequence and ack numbers and cause a disruptive ack storm. ctdb-2.5.1.dfsg/config/events.d/62.cnfs0000755000175000017500000000351212245023514017326 0ustar mathieumathieu#!/bin/sh # event script to integrate with gpfs cnfs [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig ctdb_setup_service_state_dir "gpfs" check_if_healthy() { mkdir -p "$service_state_dir/fs" [ -f "$service_state_dir/gpfsnoquorum" ] && { logger No GPFS quorum. Node is UNHEALTHY $CTDB_BASE/events.d/62.cnfs unhealthy "No GPFS quorum. Nodfe is UNHEALTHY." exit 0 } logger All required GPFS resources are available. CNFS part is healthy. $CTDB_BASE/events.d/62.cnfs healthy } case "$1" in startup) check_if_healthy ;; gpfsquorumreached) rm -f "$service_state_dir/gpfsnoquorum" logger "GPFS quorum has been reached." check_if_healthy ;; gpfsquorumloss) touch "$service_state_dir/gpfsnoquorum" logger "GPFS quorum has been lost." $CTDB_BASE/events.d/62.cnfs unhealthy "GPFS quorum was lost! Marking node as UNHEALTHY." ;; unhealthy) # Mark the node as UNHEALTHY which means all public addresses # will be migrated off the node. shift echo "$*" | ctdb_setstatus unhealthy - # force a monitor event so we pick up immediately that this script # will now fail and make the node unhealthy. ctdb eventscript monitor # Wait until we no longer serve any ip addresses at all PNN=`ctdb pnn | cut -d: -f2` while `ctdb -Y ip | cut -d: -f3 | egrep "^$PNN$" >/dev/null`; do sleep 1 done ;; healthy) # mark the node as healthy ctdb_setstatus healthy ;; monitor) ctdb_checkstatus exit $? ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/20.multipathd0000755000175000017500000000342112245023514020541 0ustar mathieumathieu#!/bin/sh # ctdb event script for monitoring the multipath daemon # # Configure monitporing of multipath devices by listing the device serials # in /etc/ctdb/multipathd : # CTDB_MONITOR_MPDEVICES="device1 device2 ..." # [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions service_name="multipathd" loadconfig [ -n "$CTDB_MONITOR_MPDEVICES" ] || exit 0 ctdb_setup_service_state_dir multipath_fail="${service_state_dir}/fail" multipathd_check_background() { for _device in $CTDB_MONITOR_MPDEVICES; do # Check multipath knows about the device _out=$(multipath -ll "$_device") if [ -z "$_out" ] ; then echo "device \"${_device}\" not known to multipathd" >"$multipath_fail" exit 1 fi # Check for at least 1 active path if ! echo "$_out" | grep 'prio=.* status=active' >/dev/null 2>&1 ; then echo "multipath device \"${_device}\" has no active paths" >"$multipath_fail" exit 1 fi done exit 0 } multipathd_check() { # Run the actual check in the background since the call to # multipath may block multipathd_check_background /dev/null 2>&1 & _pid="$!" _timeleft=10 while [ $_timeleft -gt 0 ]; do _timeleft=$(($_timeleft - 1)) # see if the process still exists kill -0 $_pid >/dev/null 2>&1 || { if wait $_pid ; then return 0 else echo -n "ERROR: " cat "$multipath_fail" rm -f "$multipath_fail" return 1 fi } sleep 1 done echo "ERROR: callout to multipath checks hung" # If hung then this probably won't work, but worth trying... kill -9 $_pid >/dev/null 2>&1 return 1 } case "$1" in monitor) multipathd_check || die "multipath monitoring failed" ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/40.fs_use0000644000175000017500000000310312245023514017646 0ustar mathieumathieu#!/bin/sh # ctdb event script for checking local file system utilization [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig case "$1" in monitor) # check each specified fs to be checked # config format is : for fs in $CTDB_CHECK_FS_USE do # parse fs_mount and fs_threshold fs_mount="${fs%:*}" fs_threshold="${fs#*:}" # check if given fs_mount is existing directory if [ ! -d "$fs_mount" ]; then echo "Directory $fs_mount does not exist" exit 1 fi # check if given fs_threshold is number if ! (echo "$fs_threshold" | egrep -q '^[0-9]+$') ; then echo "Threshold $fs_threshold is invalid number" exit 1 fi # get utilization of given fs from df fs_usage=$(df -kP $fs_mount | sed -n -e 's@.*[[:space:]]\([[:digit:]]*\)%.*@\1@p') # check if fs_usage is number if [ -z "$fs_usage" ] ; then echo "Unable to get FS utilization for $fs_mount" exit 1 fi # check if fs_usage is higher than or equal to fs_threshold if [ "$fs_usage" -ge "$fs_threshold" ] ; then echo "ERROR: Utilization of $fs_mount ($fs_usage%) is higher than threshold ($fs_threshold%)" exit 1 fi done ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/70.iscsi0000755000175000017500000000243012245023514017504 0ustar mathieumathieu#!/bin/sh # ctdb event script for TGTD based iSCSI [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions service_name="iscsi" loadconfig ctdb_start_stop_service is_ctdb_managed_service || exit 0 [ -z "$CTDB_START_ISCSI_SCRIPTS" ] && { echo "No iscsi start script directory found" exit 0 } case "$1" in ipreallocated) # block the iscsi port iptables -I INPUT 1 -p tcp --dport 3260 -j DROP # shut down the iscsi service killall -9 tgtd >/dev/null 2>/dev/null this_node=$(ctdb xpnn | sed -e 's@PNN:@@') if [ -z "$this_node" ] ; then echo "Failed to get node pnn" exit 0 fi # start the iscsi daemon tgtd >/dev/null 2>/dev/null ips=$(ctdb -Y ip | awk -F: -v pnn=$this_node '$3 == pnn {print $2}') for ip in $ips ; do script="${CTDB_START_ISCSI_SCRIPTS}/${ip}.sh" if [ -x "$script" ] ; then echo "Starting iscsi service for public address ${ip}" "$script" fi done # remove all iptables rules while iptables -D INPUT -p tcp --dport 3260 -j DROP >/dev/null 2>&1 ; do : done ;; shutdown) # shutdown iscsi when ctdb goes down killall -9 tgtd >/dev/null 2>/dev/null ;; monitor) ctdb_check_tcp_ports 3260 || exit $? ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/13.per_ip_routing0000755000175000017500000002607412245023514021426 0ustar mathieumathieu#!/bin/sh [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig service_name=per_ip_routing # Do nothing if unconfigured [ -n "$CTDB_PER_IP_ROUTING_CONF" ] || exit 0 table_id_prefix="ctdb." [ -n "$CTDB_PER_IP_ROUTING_RULE_PREF" ] || \ die "error: CTDB_PER_IP_ROUTING_RULE_PREF not configured" [ "$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" -lt "$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" ] 2>/dev/null || \ die "error: CTDB_PER_IP_ROUTING_TABLE_ID_LOW[$CTDB_PER_IP_ROUTING_TABLE_ID_LOW] and/or CTDB_PER_IP_ROUTING_TABLE_ID_HIGH[$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH] improperly configured" have_link_local_config () { [ "$CTDB_PER_IP_ROUTING_CONF" = "__auto_link_local__" ] } if ! have_link_local_config && [ ! -r "$CTDB_PER_IP_ROUTING_CONF" ] ; then die "error: CTDB_PER_IP_ROUTING_CONF=$CTDB_PER_IP_ROUTING_CONF file not found" fi ###################################################################### ipv4_is_valid_addr() { _ip="$1" _count=0 # Get the shell to break up the address into 1 word per octet for _o in $(export IFS="." ; echo $_ip) ; do # The 2>/dev/null stops output from failures where an "octet" # is not numeric. The test will still fail. if ! [ 0 -le $_o -a $_o -le 255 ] 2>/dev/null ; then return 1 fi _count=$(($_count + 1)) done # A valid IPv4 address has 4 octets [ $_count -eq 4 ] } ensure_ipv4_is_valid_addr () { _event="$1" _ip="$2" ipv4_is_valid_addr "$_ip" || { echo "$0: $_event not an ipv4 address skipping IP:$_ip" exit 0 } } ipv4_host_addr_to_net () { _host="$1" _maskbits="$2" # Convert the host address to an unsigned long by splitting out # the octets and doing the math. _host_ul=0 for _o in $(export IFS="." ; echo $_host) ; do _host_ul=$(( ($_host_ul << 8) + $_o)) # work around Emacs color bug done # Calculate the mask and apply it. _mask_ul=$(( 0xffffffff << (32 - $_maskbits) )) _net_ul=$(( $_host_ul & $_mask_ul )) # Now convert to a network address one byte at a time. _net="" for _o in $(seq 1 4) ; do _net="$(($_net_ul & 255))${_net:+.}${_net}" _net_ul=$(($_net_ul >> 8)) done echo "${_net}/${_maskbits}" } ###################################################################### # Setup a table id to use for the given IP. We don't need to know it, # it just needs to exist in /etc/iproute2/rt_tables. Fail if no free # table id could be found in the configured range. ensure_table_id_for_ip () { _ip=$1 _f="$CTDB_ETCDIR/iproute2/rt_tables" # This file should always exist, but... if [ ! -f "$_f" ] ; then mkdir -p $(dirname "$_f") touch "$_f" fi # Maintain a table id for each IP address we've ever seen in # rt_tables. We use a "ctdb." prefix on the label. _label="${table_id_prefix}${_ip}" # This finds either the table id corresponding to the label or a # new unused one (that is greater than all the used ones in the # range). ( # Note that die() just gets us out of the subshell... flock --timeout 30 0 || \ die "ensure_table_id_for_ip: failed to lock file $_f" _new=$CTDB_PER_IP_ROUTING_TABLE_ID_LOW while read _t _l ; do # Skip comments case "$_t" in \#*) continue ;; esac # Found existing: done if [ "$_l" = "$_label" ] ; then return 0 fi # Potentially update the new table id to be used. The # redirect stops error spam for a non-numeric value. if [ $_new -le $_t -a \ $_t -le $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH ] 2>/dev/null ; then _new=$(($_t + 1)) fi done # If the new table id is legal then add it to the file and # print it. if [ $_new -le $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH ] ; then printf "%d\t%s\n" "$_new" "$_label" >>"$_f" return 0 else return 1 fi ) <"$_f" } # Clean up all the table ids that we might own. clean_up_table_ids () { _f="$CTDB_ETCDIR/iproute2/rt_tables" # Even if this didn't exist on the system, adding a route will # have created it. What if we startup and immediately shutdown? if [ ! -f "$_f" ] ; then mkdir -p $(dirname "$_f") touch "$_f" fi ( # Note that die() just gets us out of the subshell... flock --timeout 30 0 || \ die "clean_up_table_ids: failed to lock file $_f" # Delete any items from the file that have a table id in our # range or a label matching our label. Preserve comments. _tmp="${_f}.$$.ctdb" awk -v min="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW" \ -v max="$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" \ -v pre="$table_id_prefix" \ '/^#/ || \ !(min <= $1 && $1 <= max) && \ !(index($2, pre) == 1) \ { print $0 }' "$_f" >"$_tmp" mv "$_tmp" "$_f" # The lock is gone - don't do anything else here ) <"$_f" } ###################################################################### # This prints the config for an IP, which is either relevant entries # from the config file or, if set to the magic link local value, some # link local routing config for the IP. get_config_for_ip () { _ip="$1" if have_link_local_config ; then # When parsing public_addresses also split on '/'. This means # that we get the maskbits as item #2 without further parsing. while IFS="/$IFS" read _i _maskbits _x ; do if [ "$_ip" = "$_i" ] ; then echo -n "$_ip "; ipv4_host_addr_to_net "$_ip" "$_maskbits" fi done <"${CTDB_PUBLIC_ADDRESSES:-/dev/null}" else while read _i _rest ; do if [ "$_ip" = "$_i" ] ; then printf "%s\t%s\n" "$_ip" "$_rest" fi done <"$CTDB_PER_IP_ROUTING_CONF" fi } ip_has_configuration () { _ip="$1" [ -n "$(get_config_for_ip $_ip)" ] } add_routing_for_ip () { _iface="$1" _ip="$2" # Do nothing if no config for this IP. ip_has_configuration "$_ip" || return 0 ensure_table_id_for_ip "$_ip" || \ die "add_routing_for_ip: out of table ids in range $CTDB_PER_IP_ROUTING_TABLE_ID_LOW - $CTDB_PER_IP_ROUTING_TABLE_ID_HIGH" _pref="$CTDB_PER_IP_ROUTING_RULE_PREF" _table_id="${table_id_prefix}${_ip}" del_routing_for_ip "$_ip" >/dev/null 2>&1 ip rule add from "$_ip" pref "$_pref" table "$_table_id" || \ die "add_routing_for_ip: failed to add rule for $_ip" # Add routes to table for any lines matching the IP. get_config_for_ip "$_ip" | while read _i _dest _gw ; do _r="$_dest ${_gw:+via} $_gw dev $_iface table $_table_id" ip route add $_r || \ die "add_routing_for_ip: failed to add route: $_r" done } del_routing_for_ip () { _ip="$1" _pref="$CTDB_PER_IP_ROUTING_RULE_PREF" _table_id="${table_id_prefix}${_ip}" # Do this unconditionally since we own any matching table ids. # However, print a meaningful message if something goes wrong. _cmd="ip rule del from $_ip pref $_pref table $_table_id" _out=$($_cmd 2>&1) || \ cat <&1 | sed -e 's@^.@ &@' } ###################################################################### flush_rules_and_routes () { ip rule show | while read _p _x _i _x _t ; do # Remove trailing colon after priority/preference. _p="${_p%:}" # Only remove rules that match our priority/preference. [ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] || continue echo "Removing ip rule for public address $_i for routing table $_t" ip rule del from "$_i" table "$_t" pref "$_p" ip route flush table "$_t" 2>/dev/null done } # Add any missing routes. Some might have gone missing if, for # example, all IPs on the network were removed (possibly if the # primary was removed). If $1 is "force" then (re-)add all the # routes. add_missing_routes () { ctdb ip -v -Y | { read _x # skip header line # Read the rest of the lines. We're only interested in the # "IP" and "ActiveInterface" columns. The latter is only set # for addresses local to this node, making it easy to skip # non-local addresses. For each IP local address we check if # the relevant routing table is populated and populate it if # not. while IFS=":" read _x _ip _x _iface _x ; do [ -n "$_iface" ] || continue _table_id="${table_id_prefix}${_ip}" if [ -z "$(ip route show table $_table_id 2>/dev/null)" -o \ "$1" = "force" ] ; then add_routing_for_ip "$_iface" "$_ip" fi done } || exit $? } # Remove rules/routes for addresses that we're not hosting. If a # releaseip event failed in an earlier script then we might not have # had a chance to remove the corresponding rules/routes. remove_bogus_routes () { # Get a IPs current hosted by this node, each anchored with '@'. _ips=$(ctdb ip -v -Y | awk -F: 'NR > 1 && $4 != "" {printf "@%s@\n", $2}') ip rule show | while read _p _x _i _x _t ; do # Remove trailing colon after priority/preference. _p="${_p%:}" # Only remove rules that match our priority/preference. [ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] || continue # Only remove rules for which we don't have an IP. This could # be done with grep, but let's do it with shell prefix removal # to avoid unnecessary processes. This falls through if # "@${_i}@" isn't present in $_ips. [ "$_ips" = "${_ips#*@${_i}@}" ] || continue echo "Removing ip rule/routes for unhosted public address $_i" del_routing_for_ip "$_i" done } ###################################################################### service_reconfigure () { add_missing_routes "force" remove_bogus_routes # flush our route cache set_proc sys/net/ipv4/route/flush 1 } ###################################################################### ctdb_check_args "$@" ctdb_service_check_reconfigure case "$1" in startup) flush_rules_and_routes # make sure that we only respond to ARP messages from the NIC # where a particular ip address is associated. get_proc sys/net/ipv4/conf/all/arp_filter >/dev/null 2>&1 && { set_proc sys/net/ipv4/conf/all/arp_filter 1 } ;; shutdown) flush_rules_and_routes clean_up_table_ids ;; takeip) iface=$2 ip=$3 maskbits=$4 ensure_ipv4_is_valid_addr "$1" "$ip" add_routing_for_ip "$iface" "$ip" # flush our route cache set_proc sys/net/ipv4/route/flush 1 ctdb gratiousarp "$ip" "$iface" ;; updateip) oiface=$2 niface=$3 ip=$4 maskbits=$5 ensure_ipv4_is_valid_addr "$1" "$ip" add_routing_for_ip "$niface" "$ip" # flush our route cache set_proc sys/net/ipv4/route/flush 1 ctdb gratiousarp "$ip" "$niface" tickle_tcp_connections "$ip" ;; releaseip) iface=$2 ip=$3 maskbits=$4 ensure_ipv4_is_valid_addr "$1" "$ip" del_routing_for_ip "$ip" ;; ipreallocated) add_missing_routes remove_bogus_routes ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/11.natgw0000755000175000017500000000622112245023514017507 0ustar mathieumathieu#!/bin/sh # Script to set up one of the nodes as a NAT gateway for all other nodes. # This is used to ensure that all nodes in the cluster can still originate # traffic to the external network even if there are no public addresses # available. # [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig [ -n "$CTDB_NATGW_NODES" ] || exit 0 export CTDB_NATGW_NODES set_natgw_capability () { # Set NATGW capability depending on configuration if [ "$CTDB_NATGW_SLAVE_ONLY" = "yes" ] ; then ctdb setnatgwstate off else ctdb setnatgwstate on fi } delete_all() { _ip="${CTDB_NATGW_PUBLIC_IP%/*}" _maskbits="${CTDB_NATGW_PUBLIC_IP#*/}" [ -z "$CTDB_NATGW_PUBLIC_IFACE" ] || { delete_ip_from_iface $CTDB_NATGW_PUBLIC_IFACE $_ip $_maskbits >/dev/null 2>&1 } ip route del 0.0.0.0/0 metric 10 >/dev/null 2>/dev/null # Delete the masquerading setup from a previous iteration where we # were the NAT-GW iptables -D POSTROUTING -t nat -s $CTDB_NATGW_PRIVATE_NETWORK ! -d $CTDB_NATGW_PRIVATE_NETWORK -j MASQUERADE >/dev/null 2>/dev/null # remove any iptables rule we may have on this address iptables -D INPUT -p tcp --syn -d $_ip/32 -j REJECT 2>/dev/null } ensure_natgwmaster () { _event="$1" set -- $(ctdb natgwlist) natgwmaster="${1:--1}" # Default is -1 if natgwlist fails natgwip="$2" if [ "$natgwmaster" = "-1" ]; then # Fail... die "There is no NATGW master node" fi } case "$1" in setup) set_natgw_capability ;; startup) # Error if CTDB_NATGW_PUBLIC_IP is listed in public addresses grep -q "^$CTDB_NATGW_PUBLIC_IP[[:space:]]" "${CTDB_PUBLIC_ADDRESSES:-/etc/ctdb/public_addresses}" && \ die "ERROR: NATGW configured to use a public address. NATGW must not use a public address." # do not send out arp requests from loopback addresses echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce ;; updatenatgw|ipreallocated) mypnn=$(ctdb pnn | cut -d: -f2) set_natgw_capability ensure_natgwmaster "$1" delete_all if [ "$mypnn" = "$natgwmaster" ]; then # This is the NAT GW echo 1 >/proc/sys/net/ipv4/ip_forward iptables -A POSTROUTING -t nat -s $CTDB_NATGW_PRIVATE_NETWORK ! -d $CTDB_NATGW_PRIVATE_NETWORK -j MASQUERADE # block all incoming connections to the natgw address ctdb_natgw_public_ip_host="${CTDB_NATGW_PUBLIC_IP%/*}/32" iptables -D INPUT -p tcp --syn -d $ctdb_natgw_public_ip_host -j REJECT 2>/dev/null iptables -I INPUT -p tcp --syn -d $ctdb_natgw_public_ip_host -j REJECT 2>/dev/null ip addr add $CTDB_NATGW_PUBLIC_IP dev $CTDB_NATGW_PUBLIC_IFACE ip route add 0.0.0.0/0 metric 10 via $CTDB_NATGW_DEFAULT_GATEWAY >/dev/null 2>/dev/null else # This is NOT the NAT GW ip route add 0.0.0.0/0 via $natgwip metric 10 # Make sure winbindd does not stay bound to this address # if we are no longer natgwmaster smbcontrol winbindd ip-dropped $CTDB_NATGW_PUBLIC_IP >/dev/null 2>/dev/null fi # flush our route cache echo 1 > /proc/sys/net/ipv4/route/flush ;; shutdown|removenatgw) delete_all ;; monitor) set_natgw_capability ensure_natgwmaster "$1" ;; *) ctdb_standard_event_handler "@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/10.interface0000755000175000017500000001704112245023514020330 0ustar mathieumathieu#!/bin/sh ################################# # interface event script for ctdb # this adds/removes IPs from your # public interface [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig [ -z "$CTDB_PUBLIC_ADDRESSES" ] && { CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses } [ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && { if [ "$1" = "init" ]; then echo "No public addresses file found. Nothing to do for 10.interfaces" fi exit 0 } mark_up () { up_interfaces_found=true ctdb setifacelink $1 up >/dev/null 2>&1 } mark_down () { fail=true ctdb setifacelink $1 down >/dev/null 2>&1 } # This sets $all_interfaces as a side-effect. get_all_interfaces () { # Get all the interfaces listed in the public_addresses file all_interfaces=$(sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//" $CTDB_PUBLIC_ADDRESSES) # Add some special interfaces if they're defined [ "$CTDB_PUBLIC_INTERFACE" ] && all_interfaces="$CTDB_PUBLIC_INTERFACE $all_interfaces" [ "$CTDB_NATGW_PUBLIC_IFACE" ] && all_interfaces="$CTDB_NATGW_PUBLIC_IFACE $all_interfaces" # Get the interfaces for which CTDB has public IPs configured. # That is, for all but the 1st line, get the 1st field. ctdb_ifaces=$(ctdb -Y ifaces | sed -e '1d' -e 's@^:@@' -e 's@:.*@@') # Add $ctdb_interfaces and uniquify all_interfaces=$(echo $all_interfaces $ctdb_ifaces | tr ' ' '\n' | sort -u) } monitor_interfaces() { get_all_interfaces fail=false up_interfaces_found=false # Note that this loop must not exit early. It must process # all interfaces so that the correct state for each interface # is set in CTDB using mark_up/mark_down. If there is a # problem with an interface then set fail=true and continue. for iface in $all_interfaces ; do ip link show $iface 2>/dev/null >/dev/null || { echo "ERROR: Interface $iface does not exist but it is used by public addresses." mark_down $iface continue } # These interfaces are sometimes bond devices # When we use VLANs for bond interfaces, there will only # be an entry in /proc for the underlying real interface realiface=`echo $iface |sed -e 's/\..*$//'` bi=$(get_proc "net/bonding/$realiface" 2>/dev/null) && { echo "$bi" | grep -q 'Currently Active Slave: None' && { echo "ERROR: No active slaves for bond device $realiface" mark_down $iface continue } echo "$bi" | grep -q '^MII Status: up' || { echo "ERROR: public network interface $realiface is down" mark_down $iface continue } echo "$bi" | grep -q '^Bonding Mode: IEEE 802.3ad Dynamic link aggregation' && { # This works around a bug in the driver where the # overall bond status can be up but none of the actual # physical interfaces have a link. echo "$bi" | grep 'MII Status:' | tail -n +2 | grep -q '^MII Status: up' || { echo "ERROR: No active slaves for 802.ad bond device $realiface" mark_down $iface continue } } mark_up $iface continue } case $iface in lo*) # loopback is always working mark_up $iface ;; ib*) # we dont know how to test ib links mark_up $iface ;; *) [ -z "$iface" ] || { [ "$(basename $(readlink /sys/class/net/$iface/device/driver) 2>/dev/null)" = virtio_net ] || ethtool $iface | grep -q 'Link detected: yes' || { # On some systems, this is not successful when a # cable is plugged but the interface has not been # brought up previously. Bring the interface up and # try again... ip link set $iface up ethtool $iface | grep -q 'Link detected: yes' || { echo "ERROR: No link on the public network interface $iface" mark_down $iface continue } } mark_up $iface } ;; esac done $fail || return 0 $up_interfaces_found && \ [ "$CTDB_PARTIALLY_ONLINE_INTERFACES" = "yes" ] && \ return 0 return 1 } ctdb_check_args "$@" case "$1" in ############################# # called when ctdbd starts up init) # make sure that we only respond to ARP messages from the NIC where # a particular ip address is associated. get_proc sys/net/ipv4/conf/all/arp_filter >/dev/null 2>&1 && { set_proc sys/net/ipv4/conf/all/arp_filter 1 } ;; ############################# # called after ctdbd has done its initial recovery # and we start the services to become healthy startup) monitor_interfaces ;; ################################################ # called when ctdbd wants to claim an IP address takeip) iface=$2 ip=$3 maskbits=$4 add_ip_to_iface $iface $ip $maskbits || { exit 1; } # cope with the script being killed while we have the interface blocked iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null # flush our route cache set_proc sys/net/ipv4/route/flush 1 ;; ################################################## # called when ctdbd wants to release an IP address releaseip) # releasing an IP is a bit more complex than it seems. Once the IP # is released, any open tcp connections to that IP on this host will end # up being stuck. Some of them (such as NFS connections) will be unkillable # so we need to use the killtcp ctdb function to kill them off. We also # need to make sure that no new connections get established while we are # doing this! So what we do is this: # 1) firewall this IP, so no new external packets arrive for it # 2) use netstat -tn to find existing connections, and kill them # 3) remove the IP from the interface # 4) remove the firewall rule iface=$2 ip=$3 maskbits=$4 failed=0 # we do an extra delete to cope with the script being killed iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null iptables -I INPUT -i $iface -d $ip -j DROP kill_tcp_connections $ip delete_ip_from_iface $iface $ip $maskbits || { iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null exit 1; } iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null # flush our route cache set_proc sys/net/ipv4/route/flush 1 ;; ################################################## # called when ctdbd wants to update an IP address updateip) # moving an IP is a bit more complex than it seems. # First we drop all traffic on the old interface. # Then we try to add the ip to the new interface and before # we finally remove it from the old interface. # # 1) firewall this IP, so no new external packets arrive for it # 2) add the IP to the new interface # 3) remove the IP from the old interface # 4) remove the firewall rule # 5) use ctdb gratiousarp to propagate the new mac address # 6) use netstat -tn to find existing connections, and tickle them oiface=$2 niface=$3 ip=$4 maskbits=$5 failed=0 # we do an extra delete to cope with the script being killed iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null iptables -I INPUT -i $oiface -d $ip -j DROP delete_ip_from_iface $oiface $ip $maskbits 2>/dev/null delete_ip_from_iface $niface $ip $maskbits 2>/dev/null add_ip_to_iface $niface $ip $maskbits || { iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null exit 1; } # cope with the script being killed while we have the interface blocked iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null # flush our route cache set_proc sys/net/ipv4/route/flush 1 # propagate the new mac address ctdb gratiousarp $ip $niface # tickle all existing connections, so that dropped packets # are retransmited and the tcp streams work tickle_tcp_connections $ip ;; monitor) monitor_interfaces || exit 1 ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/60.ganesha0000755000175000017500000001300612245023514020000 0ustar mathieumathieu#!/bin/sh # script to manage nfs in a clustered environment [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions GANRECDIR="/var/lib/nfs/ganesha" GANRECDIR2="/var/lib/nfs/ganesha/recevents" GPFS_STATE="/usr/lpp/mmfs/bin/mmgetstate" GANRECDIR3="/var/lib/nfs/ganesha_local" service_start () { startstop_ganesha stop startstop_ganesha start set_proc "sys/net/ipv4/tcp_tw_recycle" 1 } service_stop () { startstop_ganesha stop } service_reconfigure () { # if the ips have been reallocated, we must restart ganesha # across all nodes and ping all statd listeners [ -x $CTDB_BASE/statd-callout ] && { $CTDB_BASE/statd-callout notify & } >/dev/null 2>&1 } loadconfig "nfs" [ -n "$CTDB_CLUSTER_FILESYSTEM_TYPE" ] || CTDB_CLUSTER_FILESYSTEM_TYPE="gpfs" service_name="nfs-ganesha-$CTDB_CLUSTER_FILESYSTEM_TYPE" [ "${CTDB_NFS_SERVER_MODE:-${NFS_SERVER_MODE}}" = "ganesha" ] || exit 0 ctdb_setup_service_state_dir ctdb_start_stop_service is_ctdb_managed_service || exit 0 ctdb_service_check_reconfigure get_cluster_fs_state () { case $CTDB_CLUSTER_FILESYSTEM_TYPE in gpfs) STATE=`$GPFS_STATE | awk 'NR <= 3 {next} {printf "%-6s", $3}'` echo $STATE ;; *) die "File system $CTDB_CLUSTER_FILESYSTEM_TYPE not supported" ;; esac } create_ganesha_recdirs () { if [ -z "$(mount -t $CTDB_CLUSTER_FILESYSTEM_TYPE)" ]; then echo "startup $CTDB_CLUSTER_FILESYSTEM_TYPE not ready" exit 1 fi MNTPT=`mount -t $CTDB_CLUSTER_FILESYSTEM_TYPE | sort | awk '{print $3}' | head -n 1` mkdir -p $MNTPT/.ganesha if [ -e $GANRECDIR ]; then if [ ! -L $GANRECDIR ] ; then rm -rf $GANRECDIR if ! ln -s $MNTPT/.ganesha $GANRECDIR ; then echo "ln failed" fi fi else if ! ln -sf $MNTPT/.ganesha $GANRECDIR ; then echo "ln failed" fi fi mkdir -p $GANRECDIR2 mkdir -p $GANRECDIR3 } monitor_ganesha_nfsd () { create_ganesha_recdirs service_name=${service_name}_process PIDFILE="/var/run/ganesha.pid" CUR_STATE=`get_cluster_fs_state` GANESHA="/usr/bin/$CTDB_CLUSTER_FILESYSTEM_TYPE.ganesha.nfsd" if { read PID < $PIDFILE && \ grep "$GANESHA" "/proc/$PID/cmdline" ; } >/dev/null 2>&1 ; then ctdb_counter_init "$service_name" else if [ $CUR_STATE = "active" ]; then echo "Trying fast restart of NFS service" startstop_ganesha restart ctdb_counter_incr "$service_name" ctdb_check_counter "error" "-ge" "6" "$service_name" fi fi service_name="nfs-ganesha-$CTDB_CLUSTER_FILESYSTEM_TYPE"_service # check that NFS is posting forward progress if [ $CUR_STATE = "active" -a "$CTDB_NFS_SKIP_KNFSD_ALIVE_CHECK" != "yes" ] ; then MAXREDS=2 MAXSTALL=120 RESTART=0 NUMREDS=`ls $GANRECDIR3 | grep "red" | wc -l` LASTONE=`ls -t $GANRECDIR3 | sed 's/_/ /' | awk 'NR > 1 {next} {printf $1} '` # Beware of startup if [ -z $LASTONE ] ; then LASTONE=`date +"%s"` fi TNOW=$(date +"%s") TSTALL=$(($TNOW - $LASTONE)) if [ $NUMREDS -ge $MAXREDS ] ; then echo restarting because of $NUMREDS red conditions RESTART=1 ctdb_counter_incr "$service_name" ctdb_check_counter "error" "-ge" "6" "$service_name" fi if [ $TSTALL -ge $MAXSTALL ] ; then echo restarting because of $TSTALL second stall RESTART=1 ctdb_counter_incr "$service_name" ctdb_check_counter "error" "-ge" "6" "$service_name" fi if [ $RESTART -gt 0 ] ; then startstop_ganesha restart else ctdb_counter_init "$service_name" fi fi } ############################################################ case "$1" in init) # read statd from persistent database ;; startup) create_ganesha_recdirs ctdb_service_start ;; shutdown) ctdb_service_stop ;; takeip) if [ -n "$2" ] ; then case $CTDB_CLUSTER_FILESYSTEM_TYPE in gpfs) NNUM=`/usr/lpp/mmfs/bin/mmlsconfig myNodeConfigNumber | awk '{print $2}'` TDATE=`date +"%s"` TOUCHTGT=$1"_"$TDATE"_"$NNUM"_"$3"_"$4"_"$2 touch $GANRECDIR2/$TOUCHTGT ;; esac fi ctdb_service_set_reconfigure ;; releaseip) if [ -n "$2" ] ; then case $CTDB_CLUSTER_FILESYSTEM_TYPE in gpfs) NNUM=`/usr/lpp/mmfs/bin/mmlsconfig myNodeConfigNumber | awk '{print $2}'` TDATE=`date +"%s"` TOUCHTGT=$1"_"$TDATE"_"$NNUM"_"$3"_"$4"_"$2 touch $GANRECDIR2/$TOUCHTGT ;; esac fi ctdb_service_set_reconfigure ;; monitor) # Check that directories for shares actually exist. [ "$CTDB_NFS_SKIP_SHARE_CHECK" = "yes" ] || { grep Path /etc/ganesha/$CTDB_CLUSTER_FILESYSTEM_TYPE.ganesha.exports.conf | cut -f2 -d\" | sort -u | ctdb_check_directories } || exit $? update_tickles 2049 # check that statd responds to rpc requests # if statd is not running we try to restart it # we only do this IF we have a rpc.statd command. # For platforms where rpc.statd does not exist, we skip # the check completely p="rpc.statd" which $p >/dev/null 2>/dev/null && \ nfs_check_rpc_service "statd" \ -ge 6 "verbose unhealthy" \ -eq 4 "verbose restart" \ -eq 2 "restart:b" if [ "$CTDB_SKIP_GANESHA_NFSD_CHECK" != "yes" ] ; then monitor_ganesha_nfsd fi # rquotad is sometimes not started correctly on RHEL5 # not a critical service so we dont flag the node as unhealthy nfs_check_rpc_service "rquotad" \ -gt 0 "verbose restart:b" ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/01.reclock0000755000175000017500000000160512245023514020011 0ustar mathieumathieu#!/bin/sh # script to check accessibility to the reclock file on a node [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig case "$1" in init) ctdb_counter_init ;; monitor) # Early exit if not using a reclock file [ -n "$CTDB_RECOVERY_LOCK" ] || exit 0 # Try to stat the reclock file as a background process so that # we don't block in case the cluster filesystem is unavailable ( if stat $CTDB_RECOVERY_LOCK ; then # We could stat the file, reset the counter ctdb_counter_init fi ) >/dev/null 2>&1 & ctdb_counter_incr if ! ctdb_check_counter "quiet" -ge 200 ; then echo "Reclock file \"$CTDB_RECOVERY_LOCK\" can not be accessed. Shutting down." df sleep 1 ctdb shutdown fi ctdb_check_counter "error" -gt 3 ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/99.timeout0000755000175000017500000000105212245023514020072 0ustar mathieumathieu#!/bin/sh # # Event script to just sleep longer than the timeout # in the monitor action. The purpose is to trigger # the event timeout mechanism. [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig ctdb [ "$CTDB_RUN_TIMEOUT_MONITOR" = "yes" ] || exit 0 case "$1" in monitor) TIMEOUT=$(ctdb getvar EventScriptTimeout | awk '{print $3}') echo "sleeping for $((TIMEOUT * 2)) seconds..." sleep $((TIMEOUT * 2)) ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/49.winbind0000755000175000017500000000205612245023514020036 0ustar mathieumathieu#!/bin/sh # ctdb event script for winbind [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions detect_init_style CTDB_SERVICE_WINBIND=${CTDB_SERVICE_WINBIND:-winbind} service_name="winbind" loadconfig ctdb_setup_service_state_dir service_start () { service "$CTDB_SERVICE_WINBIND" stop >/dev/null 2>&1 killall -0 -q winbindd && { sleep 1 # make absolutely sure winbindd is dead killall -q -9 winbindd } service "$CTDB_SERVICE_WINBIND" start || \ die "Failed to start winbind" } service_stop () { service "$CTDB_SERVICE_WINBIND" stop } ########################### ctdb_start_stop_service is_ctdb_managed_service || exit 0 ########################### case "$1" in startup) ctdb_service_start ;; shutdown) ctdb_service_stop ;; monitor) ctdb_check_command wbinfo -p ;; takeip|releaseip) iface=$2 ip=$3 maskbits=$4 smbcontrol winbindd ip-dropped $ip >/dev/null 2>/dev/null ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/31.clamd0000755000175000017500000000141612245023514017452 0ustar mathieumathieu#!/bin/sh # event script to manage clamd in a cluster environment [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions detect_init_style case $CTDB_INIT_STYLE in redhat) service_name="clamd" service_config="clamd" ;; *) service_name="clamav" service_config="clamav" ;; esac service_start () { service $service_name stop > /dev/null 2>&1 service $service_name start } loadconfig ctdb_start_stop_service is_ctdb_managed_service || exit 0 case "$1" in startup) ctdb_service_start ;; shutdown) ctdb_service_stop ;; monitor) ctdb_check_unix_socket ${CTDB_CLAMD_SOCKET} || exit $? ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/60.nfs0000755000175000017500000000467312245023514017172 0ustar mathieumathieu#!/bin/sh # script to manage nfs in a clustered environment [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions service_name="nfs" service_start () { startstop_nfs stop startstop_nfs start set_proc "sys/net/ipv4/tcp_tw_recycle" 1 } service_stop () { startstop_nfs stop } service_reconfigure () { # if the ips have been reallocated, we must restart the lockmanager # across all nodes and ping all statd listeners [ -x $CTDB_BASE/statd-callout ] && { $CTDB_BASE/statd-callout notify & } >/dev/null 2>&1 } nfs_check_thread_count () { [ "$CTDB_MONITOR_NFS_THREAD_COUNT" = "yes" ] || return 0 # If $RPCNFSDCOUNT/$USE_KERNEL_NFSD_NUMBER isn't set then we could # guess the default from the initscript. However, let's just # assume that those using the default don't care about the number # of threads and that they have switched on this feature in error. _configured_threads="${RPCNFSDCOUNT:-${USE_KERNEL_NFSD_NUMBER}}" [ -n "$_configured_threads" ] || return 0 # nfsd should be running the configured number of threads. If # there are a different number of threads then tell nfsd the # correct number. _running_threads=$(get_proc "fs/nfsd/threads") # Intentionally not arithmetic comparison - avoids extra errors # when get_proc() fails... if [ "$_running_threads" != "$_configured_threads" ] ; then echo "Attempting to correct number of nfsd threads from ${_running_threads} to ${_configured_threads}" set_proc "fs/nfsd/threads" "$_configured_threads" fi } loadconfig [ "${CTDB_NFS_SERVER_MODE:-${NFS_SERVER_MODE}}" != "ganesha" ] || exit 0 ctdb_setup_service_state_dir ctdb_start_stop_service is_ctdb_managed_service || exit 0 ctdb_service_check_reconfigure case "$1" in init) # read statd from persistent database ;; startup) ctdb_service_start ;; shutdown) ctdb_service_stop ;; takeip) ctdb_service_set_reconfigure ;; releaseip) ctdb_service_set_reconfigure ;; monitor) # Check that directories for shares actually exist. [ "$CTDB_NFS_SKIP_SHARE_CHECK" = "yes" ] || { exportfs -v | grep '^/' | sed -r -e 's@[[:space:]]+[^[:space:]()]+\([^[:space:]()]+\)$@@' | sort -u | ctdb_check_directories } || exit $? update_tickles 2049 nfs_check_rpc_services nfs_check_thread_count ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/91.lvs0000755000175000017500000000506512245023514017210 0ustar mathieumathieu#!/bin/sh # script to manage the lvs ip multiplexer for a single public address cluster [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig ctdb [ -z "$CTDB_LVS_PUBLIC_IP" ] && exit 0 [ -z "$CTDB_PUBLIC_INTERFACE" ] && exit 0 [ -x /sbin/ipvsadm ] || { echo "LVS configured but /sbin/ipvsadm is not installed." exit 0 } case "$1" in startup) ipvsadm -D -t $CTDB_LVS_PUBLIC_IP:0 ipvsadm -D -u $CTDB_LVS_PUBLIC_IP:0 ip addr add $CTDB_LVS_PUBLIC_IP/32 dev lo scope host >/dev/null 2>/dev/null # do not respond to ARPs that are for ip addresses with scope 'host' echo 3 > /proc/sys/net/ipv4/conf/all/arp_ignore # do not send out arp requests from loopback addresses echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce ;; shutdown) ipvsadm -D -t $CTDB_LVS_PUBLIC_IP:0 ipvsadm -D -u $CTDB_LVS_PUBLIC_IP:0 # remove the ip ip addr del $CTDB_LVS_PUBLIC_IP/32 dev lo >/dev/null 2>/dev/null # flush our route cache echo 1 > /proc/sys/net/ipv4/route/flush ;; recovered|ipreallocated) # kill off any tcp connections ipvsadm -D -t $CTDB_LVS_PUBLIC_IP:0 ipvsadm -D -u $CTDB_LVS_PUBLIC_IP:0 kill_tcp_connections_local_only $CTDB_LVS_PUBLIC_IP PNN=`ctdb pnn | sed -e "s/.*PNN://"` LVSMASTER=`ctdb lvsmaster | sed -e "s/.*Node //" -e "s/ .*//"` [ "$PNN" != "$LVSMASTER" ] && { # we are not the lvs master so we have to # change the ip address to have scope host so we wont respond # to arps ip addr del $CTDB_LVS_PUBLIC_IP/32 dev lo >/dev/null 2>/dev/null ip addr add $CTDB_LVS_PUBLIC_IP/32 dev lo scope host >/dev/null 2>/dev/null exit 0 } # change the scope so we start responding to arps ip addr del $CTDB_LVS_PUBLIC_IP/32 dev lo >/dev/null 2>/dev/null ip addr add $CTDB_LVS_PUBLIC_IP/32 dev lo >/dev/null 2>/dev/null ipvsadm -A -t $CTDB_LVS_PUBLIC_IP:0 -p 1999999 -s lc ipvsadm -A -u $CTDB_LVS_PUBLIC_IP:0 -p 1999999 -s lc # add all nodes (except ourselves) to the lvs config ctdb lvs | egrep -v "^$PNN:" | sed -e "s/.*://" | while read IP; do ipvsadm -a -t $CTDB_LVS_PUBLIC_IP:0 -r $IP -g ipvsadm -a -u $CTDB_LVS_PUBLIC_IP:0 -r $IP -g done # and add the localhost too ipvsadm -a -t $CTDB_LVS_PUBLIC_IP:0 -r 127.0.0.1 ipvsadm -a -u $CTDB_LVS_PUBLIC_IP:0 -r 127.0.0.1 # send out a gratious arp so our peers will update their arp tables ctdb gratiousarp $CTDB_LVS_PUBLIC_IP $CTDB_PUBLIC_INTERFACE >/dev/null 2>/dev/null # flush our route cache echo 1 > /proc/sys/net/ipv4/route/flush ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/41.httpd0000755000175000017500000000270512245023514017520 0ustar mathieumathieu#!/bin/sh # event script to manage httpd in a cluster environment [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions detect_init_style case $CTDB_INIT_STYLE in redhat) service_name="httpd" service_config="http" ;; suse|debian|*) service_name="apache2" service_config="apache2" ;; esac # RHEL5 sometimes use a SIGKILL to terminate httpd, which then leaks # semaphores. This is a hack to clean them up. cleanup_httpd_semaphore_leak() { killall -q -0 "$service_name" || for i in $(ipcs -s | awk '$3 == "apache" { print $2 }') ; do ipcrm -s $i done } ########## service_start () { cleanup_httpd_semaphore_leak service $service_name start } service_stop () { service $service_name stop killall -q -9 $service_name || true } loadconfig ctdb_start_stop_service is_ctdb_managed_service || exit 0 case "$1" in startup) ctdb_service_start ;; shutdown) ctdb_service_stop ;; monitor) if ctdb_check_tcp_ports 80 >/dev/null 2>/dev/null ; then ctdb_counter_init else ctdb_counter_incr ctdb_check_counter warn -eq 2 || { echo "HTTPD is not running. Trying to restart HTTPD." service_stop service_start exit 0 } ctdb_check_counter warn -ge 5 || { echo "HTTPD is not running. Trying to restart HTTPD." service_stop service_start exit 1 } fi ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/40.vsftpd0000755000175000017500000000221512245023514017676 0ustar mathieumathieu#!/bin/sh # event strict to manage vsftpd in a cluster environment [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions service_name="vsftpd" # make sure the service is stopped first service_start () { service $service_name stop > /dev/null 2>&1 service $service_name start } service_stop () { service $service_name stop } service_reconfigure () { service $service_name restart } service_fail_limit=2 service_tcp_ports=21 loadconfig ctdb_start_stop_service is_ctdb_managed_service || exit 0 ctdb_service_check_reconfigure case "$1" in startup) ctdb_service_start ;; shutdown) ctdb_service_stop ;; takeip|releaseip) ctdb_service_set_reconfigure ;; monitor) if [ -n "$service_tcp_ports" ] ; then if ctdb_check_tcp_ports $service_tcp_ports ; then ctdb_counter_init else ctdb_counter_incr ctdb_check_counter ctdb_check_counter "quiet" -ge 1 || \ echo "WARNING: vsftpd not listening but less than $service_fail_limit consecutive failures, not unhealthy yet" fi fi ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/50.samba0000755000175000017500000000664312245023514017465 0ustar mathieumathieu#!/bin/sh # ctdb event script for Samba [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions detect_init_style case $CTDB_INIT_STYLE in suse) CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb} CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-nmb} ;; debian) CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-samba} CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""} ;; *) # Use redhat style as default: CTDB_SERVICE_SMB=${CTDB_SERVICE_SMB:-smb} CTDB_SERVICE_NMB=${CTDB_SERVICE_NMB:-""} ;; esac service_name="samba" loadconfig ctdb_setup_service_state_dir service_start () { # make sure samba is not already started service "$CTDB_SERVICE_SMB" stop > /dev/null 2>&1 if [ -n "$CTDB_SERVICE_NMB" ] ; then service "$CTDB_SERVICE_NMB" stop > /dev/null 2>&1 fi killall -0 -q smbd && { sleep 1 # make absolutely sure samba is dead killall -q -9 smbd } killall -0 -q nmbd && { sleep 1 # make absolutely sure samba is dead killall -q -9 nmbd } # start Samba service. Start it reniced, as under very heavy load # the number of smbd processes will mean that it leaves few cycles # for anything else net serverid wipe if [ -n "$CTDB_SERVICE_NMB" ] ; then nice_service "$CTDB_SERVICE_NMB" start || die "Failed to start nmbd" fi nice_service "$CTDB_SERVICE_SMB" start || die "Failed to start samba" } service_stop () { service "$CTDB_SERVICE_SMB" stop if [ -n "$CTDB_SERVICE_NMB" ] ; then service "$CTDB_SERVICE_NMB" stop fi } ###################################################################### # Show the testparm output using a cached smb.conf to avoid delays due # to registry access. smbconf_cache="$service_state_dir/smb.conf.cache" testparm_foreground_update () { _timeout="$1" if ! _out=$(timeout $_timeout testparm -v -s 2>/dev/null) ; then if [ -f "$smbconf_cache" ] ; then echo "WARNING: smb.conf cache update failed - using old cache file" return 1 else die "ERROR: smb.conf cache create failed" fi fi _tmpfile="${smbconf_cache}.$$" # Patterns to exclude... pat='^[[:space:]]+(registry[[:space:]]+shares|include|copy|winbind[[:space:]]+separator)[[:space:]]+=' echo "$_out" | grep -Ev "$pat" >"$_tmpfile" mv "$_tmpfile" "$smbconf_cache" # atomic return 0 } testparm_background_update () { _timeout="$1" testparm_foreground_update $_timeout >/dev/null 2>&1 /dev/null } list_samba_shares () { testparm_cat | sed -n -e 's@^[[:space:]]*path[[:space:]]*=[[:space:]]@@p' | sed -e 's/"//g' } list_samba_ports () { testparm_cat --parameter-name="smb ports" | sed -e 's@,@ @g' } ########################### ctdb_start_stop_service is_ctdb_managed_service || exit 0 ########################### case "$1" in startup) ctdb_service_start ;; shutdown) ctdb_service_stop ;; monitor) testparm_foreground_update 10 ret=$? smb_ports="$CTDB_SAMBA_CHECK_PORTS" if [ -z "$smb_ports" ] ; then smb_ports=$(list_samba_ports) [ -n "$smb_ports" ] || die "Failed to set smb ports" fi ctdb_check_tcp_ports $smb_ports || exit $? if [ "$CTDB_SAMBA_SKIP_SHARE_CHECK" != "yes" ] ; then list_samba_shares | ctdb_check_directories || exit $? fi if [ $ret -ne 0 ] ; then testparm_background_update 10 fi ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/11.routing0000755000175000017500000000211612245023514020055 0ustar mathieumathieu#!/bin/sh # script to add entries to the routing table after we have performed a # take ip event # (when we do a "releaseip" event and remove an ip address from an interface # the kernel might automatically remove associated entries from # the routing table. This is where we add them back) # # Routes to add are defined in /etc/ctdb/static-routes. # Syntax is : # IFACE NET/MASK GATEWAY # # Example # bond1 10.3.3.0/24 10.0.0.1 [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig [ -f $CTDB_BASE/static-routes ] || { exit 0 } case "$1" in ipreallocated) while read iface dest gw; do ip route add "$dest" via "$gw" dev "$iface" >/dev/null 2>&1 done <"${CTDB_BASE}/static-routes" ;; updateip) oiface=$2 niface=$3 while read iface dest gw; do if [ "$niface" = "$iface" -o "$oiface" = "$iface" ] ; then ip route add "$dest" via "$gw" dev "$iface" >/dev/null 2>&1 fi done <"${CTDB_BASE}/static-routes" ;; *) ctdb_standard_event_handler "$@" ;; esac exit 0 ctdb-2.5.1.dfsg/config/events.d/00.ctdb0000755000175000017500000001263012245023514017302 0ustar mathieumathieu#!/bin/sh # Event script for ctdb-specific setup and other things that don't fit # elsewhere. [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; dirname "$PWD") . $CTDB_BASE/functions loadconfig ctdb_setup_service_state_dir "ctdb" ############################################################ select_tdb_checker () { # Find the best TDB consistency check available. use_tdb_tool_check=false if which tdbtool >/dev/null 2>&1 && \ echo "help" | tdbtool | grep -q check ; then use_tdb_tool_check=true elif which tdbtool >/dev/null 2>&1 && which tdbdump >/dev/null 2>&1 ; then cat </dev/null 2>&1 ; then cat </dev/null | grep -q "Database integrity is OK" ; then return 0 else return 1 fi else tdbdump "$_db" >/dev/null 2>/dev/null return $? fi } check_persistent_databases () { _dir="${CTDB_DBDIR_PERSISTENT:-${CTDB_DBDIR:-${CTDB_VARDIR}}/persistent}" mkdir -p "$_dir" 2>/dev/null [ "${CTDB_MAX_PERSISTENT_CHECK_ERRORS:-0}" = "0" ] || return 0 for _db in $(ls "$_dir/"*.tdb.*[0-9] 2>/dev/null) ; do check_tdb $_db || { echo "Persistent database $_db is corrupted! CTDB will not start." return 1 } done } check_non_persistent_databases () { _dir="${CTDB_DBDIR:-${CTDB_VARDIR}}" mkdir -p "$_dir" 2>/dev/null for _db in $(ls "${_dir}/"*.tdb.*[0-9] 2>/dev/null) ; do check_tdb $_db || { _backup="${_db}.$(date +'%Y%m%d.%H%M%S.%N').corrupt" cat </dev/null && \ [ -s "$_t" -a -n "$CTDB_PUBLIC_ADDRESSES"] && \ ! cmp -s "$_t" "$CTDB_PUBLIC_ADDRESSES" ; then echo "CTDB public address configuration has changed." echo "Extracting new configuration from database." diff "$_t" "$CTDB_PUBLIC_ADDRESSES" cp "$_t" "$CTDB_PUBLIC_ADDRESSES" echo "Restarting CTDB" service ctdb restart & fi } set_ctdb_variables () { # set any tunables from the config file set | grep ^CTDB_SET_ | cut -d_ -f3- | while read v; do varname=`echo $v | cut -d= -f1` value=`echo $v | cut -d= -f2` ctdb setvar $varname $value || return 1 echo "Set $varname to $value" done } monitor_system_memory () { # If monitoring free memory then calculate how much there is if [ -n "$CTDB_MONITOR_FREE_MEMORY_WARN" -o \ -n "$CTDB_MONITOR_FREE_MEMORY" ] ; then free_mem=$(free -m | awk '$2 == "buffers/cache:" { print $4 }') fi # Shutdown CTDB when memory is below the configured limit if [ -n "$CTDB_MONITOR_FREE_MEMORY" ] ; then if [ $free_mem -le $CTDB_MONITOR_FREE_MEMORY ] ; then echo "CRITICAL: OOM - ${free_mem}MB free <= ${CTDB_MONITOR_FREE_MEMORY}MB (CTDB threshold)" echo "CRITICAL: Shutting down CTDB!!!" get_proc "meminfo" ps auxfww set_proc "sysrq-trigger" "m" ctdb disable sleep 3 ctdb shutdown fi fi # Warn when low on memory if [ -n "$CTDB_MONITOR_FREE_MEMORY_WARN" ] ; then if [ $free_mem -le $CTDB_MONITOR_FREE_MEMORY_WARN ] ; then echo "WARNING: free memory is low - ${free_mem}MB free <= ${CTDB_MONITOR_FREE_MEMORY_WARN}MB (CTDB threshold)" fi fi # We should never enter swap, so SwapTotal == SwapFree. if [ "$CTDB_CHECK_SWAP_IS_NOT_USED" = "yes" ] ; then set -- $(get_proc "meminfo" | awk '$1 ~ /Swap(Total|Free):/ { print $2 }') if [ "$1" != "$2" ] ; then echo We are swapping: get_proc "meminfo" ps auxfww fi fi } ############################################################ ctdb_check_args "$@" case "$1" in init) # make sure we have a blank state directory for the scripts to work with rm -rf $CTDB_VARDIR/state # Look at the pattern - this should not be -rf!!! rm -f $ctdb_managed_dir/* mkdir -p $CTDB_VARDIR/state || { ret=$? echo "mkdir -p $CTDB_VARDIR/state - failed - $ret" exit $ret } # make sure we drop any ips that might still be held if # previous instance of ctdb got killed with -9 or similar drop_all_public_ips if select_tdb_checker ; then check_persistent_databases || exit $? check_non_persistent_databases fi ;; setup) # Set any tunables from the config file set_ctdb_variables || die "Failed to set CTDB tunables" ;; startup) update_config_from_tdb & ;; monitor) monitor_system_memory ;; *) ctdb_standard_event_handler "$@" ;; esac # all OK exit 0 ctdb-2.5.1.dfsg/config/ctdb.sysconfig0000644000175000017500000000175612245023514017345 0ustar mathieumathieu# Options to ctdbd, read by ctdbd_wrapper(1) # # See ctdbd.conf(5) for more information about CTDB configuration variables. # Shared recovery lock file to avoid split brain. No default. # # Do NOT run CTDB without a recovery lock file unless you know exactly # what you are doing. CTDB_RECOVERY_LOCK=/some/place/on/shared/storage # List of nodes in the cluster. Default is below. # CTDB_NODES=/etc/ctdb/nodes # List of public addresses for providing NAS services. No default. CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses # What services should CTDB manage? Default is none. # CTDB_MANAGES_SAMBA=yes # CTDB_MANAGES_WINBIND=yes # CTDB_MANAGES_NFS=yes # Raise the file descriptor limit for CTDB? # ulimit -n 10000 # Default is to use the log file below instead of syslog. # CTDB_LOGFILE=/var/log/log.ctdb # CTDB_SYSLOG=no # Default log level is ERR. NOTICE is a little more verbose. CTDB_DEBUGLEVEL=NOTICE # Set some CTDB tunable variables during CTDB startup? # CTDB_SET_TraverseTimeout=60 ctdb-2.5.1.dfsg/config/functions0000755000175000017500000010553612245023514016442 0ustar mathieumathieu# Hey Emacs, this is a -*- shell-script -*- !!! # utility functions for ctdb event scripts [ -z "$CTDB_VARDIR" ] && { if [ -d "/var/lib/ctdb" ] ; then export CTDB_VARDIR="/var/lib/ctdb" else export CTDB_VARDIR="/var/ctdb" fi } [ -z "$CTDB_ETCDIR" ] && { export CTDB_ETCDIR="/etc" } ####################################### # pull in a system config file, if any _loadconfig() { if [ -z "$1" ] ; then foo="${service_config:-${service_name}}" if [ -n "$foo" ] ; then loadconfig "$foo" return fi fi if [ "$1" != "ctdb" ] ; then loadconfig "ctdb" fi if [ -z "$1" ] ; then return fi if [ -f $CTDB_ETCDIR/sysconfig/$1 ]; then . $CTDB_ETCDIR/sysconfig/$1 elif [ -f $CTDB_ETCDIR/default/$1 ]; then . $CTDB_ETCDIR/default/$1 elif [ -f $CTDB_BASE/sysconfig/$1 ]; then . $CTDB_BASE/sysconfig/$1 fi if [ "$1" = "ctdb" ] ; then _config="${CTDB_BASE}/ctdbd.conf" if [ -r "$_config" ] ; then . "$_config" fi fi } loadconfig () { _loadconfig "$@" } ############################################################## # CTDB_SCRIPT_DEBUGLEVEL can be overwritten by setting it in a # configuration file. debug () { if [ ${CTDB_SCRIPT_DEBUGLEVEL:-2} -ge 4 ] ; then # If there are arguments then echo them. Otherwise expect to # use stdin, which allows us to pass lots of debug using a # here document. if [ -n "$1" ] ; then echo "DEBUG: $*" elif ! tty -s ; then sed -e 's@^@DEBUG: @' fi fi } die () { _msg="$1" _rc="${2:-1}" echo "$_msg" exit $_rc } # Log given message or stdin to either syslog or a CTDB log file # $1 is the tag passed to logger if syslog is in use. script_log () { _tag="$1" ; shift if [ "$CTDB_SYSLOG" = "yes" ] ; then logger -t "ctdbd: ${_tag}" $* else { if [ -n "$*" ] ; then echo "$*" else cat fi } >>"${CTDB_LOGFILE:-/var/log/log.ctdb}" fi } # When things are run in the background in an eventscript then logging # output might get lost. This is the "solution". :-) background_with_logging () { ( "$@" 2>&1 "/proc/$1" } ###################################################### # wrapper around getting file contents from /proc/ to allow # this to be hooked for testing # 1st arg is relative path under /proc/ get_proc () { cat "/proc/$1" } ###################################################### # Check that an RPC service is healthy - # this includes allowing a certain number of failures # before marking the NFS service unhealthy. # # usage: nfs_check_rpc_service SERVICE_NAME [ triple ...] # # each triple is a set of 3 arguments: an operator, a # fail count limit and an action string. # # For example: # # nfs_check_rpc_service "lockd" \ # -ge 15 "verbose restart unhealthy" \ # -eq 10 "restart:bs" # # says that if lockd is down for 15 iterations then do # a verbose restart of lockd and mark the node unhealthy. # Before this, after 10 iterations of failure, the # service is restarted silently in the background. # Order is important: the number of failures need to be # specified in reverse order because processing stops # after the first condition that is true. ###################################################### nfs_check_rpc_service () { _prog_name="$1" ; shift if _nfs_check_rpc_common "$_prog_name" ; then return fi while [ -n "$3" ] ; do if _nfs_check_rpc_action "$1" "$2" "$3" ; then break fi shift 3 done } # The new way of doing things... nfs_check_rpc_services () { # Files must end with .check - avoids editor backups, RPM fu, ... for _f in "${CTDB_BASE}/nfs-rpc-checks.d/"[0-9][0-9].*.check ; do _t="${_f%.check}" _prog_name="${_t##*/[0-9][0-9].}" if _nfs_check_rpc_common "$_prog_name" ; then # This RPC service is up, check next service... continue fi # Check each line in the file in turn until one of the limit # checks is hit... while read _cmp _lim _rest ; do # Skip comments case "$_cmp" in \#*) continue ;; esac if _nfs_check_rpc_action "$_cmp" "$_lim" "$_rest" ; then # Limit was hit on this line, no further checking... break fi done <"$_f" done } _nfs_check_rpc_common () { _prog_name="$1" # Some platforms don't have separate programs for all services. case "$_prog_name" in statd) which "rpc.${_prog_name}" >/dev/null 2>&1 || return 0 esac case "$_prog_name" in nfsd) _rpc_prog=nfs _version=3 ;; mountd) _rpc_prog=mountd _version=1 ;; rquotad) _rpc_prog=rquotad _version=1 ;; lockd) _rpc_prog=nlockmgr _version=4 ;; statd) _rpc_prog=status _version=1 ;; *) echo "Internal error: unknown RPC program \"$_prog_name\"." exit 1 esac _service_name="nfs_${_prog_name}" if ctdb_check_rpc "$_rpc_prog" $_version >/dev/null ; then ctdb_counter_init "$_service_name" return 0 fi ctdb_counter_incr "$_service_name" return 1 } _nfs_check_rpc_action () { _cmp="$1" _limit="$2" _actions="$3" if ctdb_check_counter "quiet" "$_cmp" "$_limit" "$_service_name" ; then return 1 fi for _action in $_actions ; do case "$_action" in verbose) echo "$ctdb_check_rpc_out" ;; restart) _nfs_restart_rpc_service "$_prog_name" ;; restart:b) _nfs_restart_rpc_service "$_prog_name" true ;; unhealthy) exit 1 ;; *) echo "Internal error: unknown action \"$_action\"." exit 1 esac done return 0 } _nfs_restart_rpc_service () { _prog_name="$1" _background="${2:-false}" if $_background ; then _maybe_background="background_with_logging" else _maybe_background="" fi _p="rpc.${_prog_name}" case "$_prog_name" in nfsd) echo "Trying to restart NFS service" $_maybe_background startstop_nfs restart ;; mountd) echo "Trying to restart $_prog_name [${_p}]" killall -q -9 "$_p" $_maybe_background $_p ${MOUNTD_PORT:+-p} $MOUNTD_PORT ;; rquotad) echo "Trying to restart $_prog_name [${_p}]" killall -q -9 "$_p" $_maybe_background $_p ${RQUOTAD_PORT:+-p} $RQUOTAD_PORT ;; lockd) echo "Trying to restart lock manager service" $_maybe_background startstop_nfslock restart ;; statd) echo "Trying to restart $_prog_name [${_p}]" killall -q -9 "$_p" $_maybe_background $_p \ ${STATD_HOSTNAME:+-n} $STATD_HOSTNAME \ ${STATD_PORT:+-p} $STATD_PORT \ ${STATD_OUTGOING_PORT:+-o} $STATD_OUTGOING_PORT ;; *) echo "Internal error: unknown RPC program \"$_prog_name\"." exit 1 esac } ###################################################### # check that a rpc server is registered with portmap # and responding to requests # usage: ctdb_check_rpc SERVICE_NAME VERSION ###################################################### ctdb_check_rpc () { progname="$1" version="$2" _localhost="${CTDB_RPCINFO_LOCALHOST:-127.0.0.1}" if ! ctdb_check_rpc_out=$(rpcinfo -u $_localhost $progname $version 2>&1) ; then ctdb_check_rpc_out="ERROR: $progname failed RPC check: $ctdb_check_rpc_out" echo "$ctdb_check_rpc_out" return 1 fi } ###################################################### # Ensure $service_name is set assert_service_name () { [ -n "$service_name" ] || die "INTERNAL ERROR: \$service_name not set" } ###################################################### # check a set of directories is available # return 1 on a missing directory # directories are read from stdin ###################################################### ctdb_check_directories_probe() { while IFS="" read d ; do case "$d" in *%*) continue ;; *) [ -d "${d}/." ] || return 1 esac done } ###################################################### # check a set of directories is available # directories are read from stdin ###################################################### ctdb_check_directories() { ctdb_check_directories_probe || { echo "ERROR: $service_name directory \"$d\" not available" exit 1 } } ###################################################### # check a set of tcp ports # usage: ctdb_check_tcp_ports ###################################################### # This flag file is created when a service is initially started. It # is deleted the first time TCP port checks for that service succeed. # Until then ctdb_check_tcp_ports() prints a more subtle "error" # message if a port check fails. _ctdb_check_tcp_common () { assert_service_name _ctdb_service_started_file="$ctdb_fail_dir/$service_name.started" } ctdb_check_tcp_init () { _ctdb_check_tcp_common mkdir -p "${_ctdb_service_started_file%/*}" # dirname touch "$_ctdb_service_started_file" } # Check whether something is listening on all of the given TCP ports # using the "ctdb checktcpport" command. ctdb_check_tcp_ports() { if [ -z "$1" ] ; then echo "INTERNAL ERROR: ctdb_check_tcp_ports - no ports specified" exit 1 fi for _p ; do # process each function argument (port) _cmd="ctdb checktcpport $_p" _out=$($_cmd 2>&1) _ret=$? case "$_ret" in 0) _ctdb_check_tcp_common if [ ! -f "$_ctdb_service_started_file" ] ; then echo "ERROR: $service_name tcp port $_p is not responding" debug "\"ctdb checktcpport $_p\" was able to bind to port" else echo "INFO: $service_name tcp port $_p is not responding" fi return 1 ;; 98) # Couldn't bind, something already listening, next port... continue ;; *) echo "ERROR: unexpected error running \"ctdb checktcpport\"" debug < ###################################################### ctdb_check_unix_socket() { socket_path="$1" [ -z "$socket_path" ] && return if ! netstat --unix -a -n | grep -q "^unix.*LISTEN.*${socket_path}$"; then echo "ERROR: $service_name socket $socket_path not found" return 1 fi } ###################################################### # check a command returns zero status # usage: ctdb_check_command ###################################################### ctdb_check_command () { _out=$("$@" 2>&1) || { echo "ERROR: $* returned error" echo "$_out" | debug exit 1 } } ################################################ # kill off any TCP connections with the given IP ################################################ kill_tcp_connections () { _ip="$1" _oneway=false if [ "$2" = "oneway" ] ; then _oneway=true fi get_tcp_connections_for_ip "$_ip" | { _killcount=0 _connections="" _nl=" " while read _dst _src; do _destport="${_dst##*:}" __oneway=$_oneway case $_destport in # we only do one-way killtcp for CIFS 139|445) __oneway=true ;; esac echo "Killing TCP connection $_src $_dst" _connections="${_connections}${_nl}${_src} ${_dst}" if ! $__oneway ; then _connections="${_connections}${_nl}${_dst} ${_src}" fi _killcount=$(($_killcount + 1)) done if [ $_killcount -eq 0 ] ; then return fi echo "$_connections" | ctdb killtcp || { echo "Failed to send killtcp control" return } _count=0 while : ; do _remaining=$(get_tcp_connections_for_ip $_ip | wc -l) if [ $_remaining -eq 0 ] ; then echo "Killed $_killcount TCP connections to released IP $_ip" return fi _count=$(($_count + 1)) if [ $_count -gt 3 ] ; then echo "Timed out killing tcp connections for IP $_ip" return fi echo "Waiting for $_remaining connections to be killed for IP $_ip" sleep 1 done } } ################################################################## # kill off the local end for any TCP connections with the given IP ################################################################## kill_tcp_connections_local_only () { kill_tcp_connections "$1" "oneway" } ################################################################## # tickle any TCP connections with the given IP ################################################################## tickle_tcp_connections () { _ip="$1" get_tcp_connections_for_ip "$_ip" | { _failed=false while read dest src; do echo "Tickle TCP connection $src $dest" ctdb tickle $src $dest >/dev/null 2>&1 || _failed=true echo "Tickle TCP connection $dest $src" ctdb tickle $dest $src >/dev/null 2>&1 || _failed=true done if $_failed ; then echo "Failed to send tickle control" fi } } get_tcp_connections_for_ip () { _ip="$1" netstat -tn | awk -v ip=$_ip \ 'index($1, "tcp") == 1 && \ (index($4, ip ":") == 1 || index($4, "::ffff:" ip ":") == 1) \ && $6 == "ESTABLISHED" \ {print $4" "$5}' } ######################################################## # start/stop the Ganesha nfs service ######################################################## startstop_ganesha() { _service_name="nfs-ganesha-$CTDB_CLUSTER_FILESYSTEM_TYPE" case "$1" in start) service "$_service_name" start ;; stop) service "$_service_name" stop ;; restart) service "$_service_name" restart ;; esac } ######################################################## # start/stop the nfs service on different platforms ######################################################## startstop_nfs() { PLATFORM="unknown" [ -x $CTDB_ETCDIR/init.d/nfsserver ] && { PLATFORM="sles" } [ -x $CTDB_ETCDIR/init.d/nfslock ] && { PLATFORM="rhel" } case $PLATFORM in sles) case $1 in start) service nfsserver start ;; stop) service nfsserver stop > /dev/null 2>&1 ;; restart) set_proc "fs/nfsd/threads" 0 service nfsserver stop > /dev/null 2>&1 pkill -9 nfsd nfs_dump_some_threads service nfsserver start ;; esac ;; rhel) case $1 in start) service nfslock start service nfs start ;; stop) service nfs stop service nfslock stop ;; restart) set_proc "fs/nfsd/threads" 0 service nfs stop > /dev/null 2>&1 service nfslock stop > /dev/null 2>&1 pkill -9 nfsd nfs_dump_some_threads service nfslock start service nfs start ;; esac ;; *) echo "Unknown platform. NFS is not supported with ctdb" exit 1 ;; esac } # Dump up to the configured number of nfsd thread backtraces. nfs_dump_some_threads () { [ -n "$CTDB_NFS_DUMP_STUCK_THREADS" ] || return 0 # Optimisation to avoid running an unnecessary pidof [ $CTDB_NFS_DUMP_STUCK_THREADS -gt 0 ] || return 0 _count=0 for _pid in $(pidof nfsd) ; do [ $_count -le $CTDB_NFS_DUMP_STUCK_THREADS ] || break # Do this first to avoid racing with thread exit _stack=$(get_proc "${_pid}/stack" 2>/dev/null) if [ -n "$_stack" ] ; then echo "Stack trace for stuck nfsd thread [${_pid}]:" echo "$_stack" _count=$(($_count + 1)) fi done } ######################################################## # start/stop the nfs lockmanager service on different platforms ######################################################## startstop_nfslock() { PLATFORM="unknown" [ -x $CTDB_ETCDIR/init.d/nfsserver ] && { PLATFORM="sles" } [ -x $CTDB_ETCDIR/init.d/nfslock ] && { PLATFORM="rhel" } case $PLATFORM in sles) # for sles there is no service for lockmanager # so we instead just shutdown/restart nfs case $1 in start) service nfsserver start ;; stop) service nfsserver stop > /dev/null 2>&1 ;; restart) service nfsserver stop > /dev/null 2>&1 service nfsserver start ;; esac ;; rhel) case $1 in start) service nfslock start ;; stop) service nfslock stop > /dev/null 2>&1 ;; restart) service nfslock stop > /dev/null 2>&1 service nfslock start ;; esac ;; *) echo "Unknown platform. NFS locking is not supported with ctdb" exit 1 ;; esac } # Periodically update the statd database nfs_statd_update () { _update_period="$1" _statd_update_trigger="$service_state_dir/update-trigger" [ -f "$_statd_update_trigger" ] || touch "$_statd_update_trigger" _last_update=$(stat --printf="%Y" "$_statd_update_trigger") _current_time=$(date +"%s") if [ $(( $_current_time - $_last_update)) -ge $_update_period ] ; then touch "$_statd_update_trigger" $CTDB_BASE/statd-callout updatelocal & $CTDB_BASE/statd-callout updateremote & fi } add_ip_to_iface() { _iface=$1 _ip=$2 _maskbits=$3 _lockfile="${CTDB_VARDIR}/state/interface_modify_${_iface}.flock" mkdir -p "${_lockfile%/*}" # dirname [ -f "$_lockfile" ] || touch "$_lockfile" ( # Note: use of return/exit/die() below only gets us out of the # sub-shell, which is actually what we want. That is, the # function should just return non-zero. flock --timeout 30 0 || \ die "add_ip_to_iface: unable to get lock for ${_iface}" # Ensure interface is up ip link set "$_iface" up || \ die "Failed to bringup interface $_iface" ip addr add "$_ip/$_maskbits" brd + dev "$_iface" || \ die "Failed to add $_ip/$_maskbits on dev $_iface" ) <"$_lockfile" # Do nothing here - return above only gets us out of the subshell # and doing anything here will affect the return code. } delete_ip_from_iface() { _iface=$1 _ip=$2 _maskbits=$3 _lockfile="${CTDB_VARDIR}/state/interface_modify_${_iface}.flock" mkdir -p "${_lockfile%/*}" # dirname [ -f "$_lockfile" ] || touch "$_lockfile" ( # Note: use of return/exit/die() below only gets us out of the # sub-shell, which is actually what we want. That is, the # function should just return non-zero. flock --timeout 30 0 || \ die "delete_ip_from_iface: unable to get lock for ${_iface}" _im="$_ip/$_maskbits" # shorthand for readability # "ip addr del" will delete all secondary IPs if this is the # primary. To work around this _very_ annoying behaviour we # have to keep a record of the secondaries and re-add them # afterwards. Yuck! _secondaries="" if ip addr list dev "$_iface" primary | grep -Fq "inet $_im " ; then _secondaries=$(ip addr list dev "$_iface" secondary | \ awk '$1 == "inet" { print $2 }') fi local _rc=0 ip addr del "$_im" dev "$_iface" || { echo "Failed to del $_ip on dev $_iface" _rc=1 } if [ -n "$_secondaries" ] ; then for _i in $_secondaries; do if ip addr list dev "$_iface" | grep -Fq "inet $_i" ; then echo "Kept secondary $_i on dev $_iface" else echo "Re-adding secondary address $_i to dev $_iface" ip addr add $_i brd + dev $_iface || { echo "Failed to re-add address $_i to dev $_iface" _rc=1 } fi done fi return $_rc ) <"$_lockfile" # Do nothing here - return above only gets us out of the subshell # and doing anything here will affect the return code. } # If the given IP is hosted then print 2 items: maskbits and iface ip_maskbits_iface () { _addr="$1" ip addr show to "${_addr}/32" 2>/dev/null | \ awk '$1 == "inet" { print gensub(".*/", "", 1, $2), $NF }' } drop_ip () { _addr="${1%/*}" # Remove optional maskbits set -- $(ip_maskbits_iface $_addr) if [ -n "$1" ] ; then _maskbits="$1" _iface="$2" echo "Removing public address $_addr/$_maskbits from device $_iface" delete_ip_from_iface $_iface $_addr $_maskbits >/dev/null 2>&1 fi } drop_all_public_ips () { while read _ip _x ; do drop_ip "$_ip" done <"${CTDB_PUBLIC_ADDRESSES:-/dev/null}" } ######################################################## # Simple counters _ctdb_counter_common () { _service_name="${1:-${service_name:-${script_name}}}" _counter_file="$ctdb_fail_dir/$_service_name" mkdir -p "${_counter_file%/*}" # dirname } ctdb_counter_init () { _ctdb_counter_common "$1" >"$_counter_file" } ctdb_counter_incr () { _ctdb_counter_common "$1" # unary counting! echo -n 1 >> "$_counter_file" } ctdb_check_counter () { _msg="${1:-error}" # "error" - anything else is silent on fail _op="${2:--ge}" # an integer operator supported by test _limit="${3:-${service_fail_limit}}" shift 3 _ctdb_counter_common "$1" # unary counting! _size=$(stat -c "%s" "$_counter_file" 2>/dev/null || echo 0) _hit=false if [ "$_op" != "%" ] ; then if [ $_size $_op $_limit ] ; then _hit=true fi else if [ $(($_size $_op $_limit)) -eq 0 ] ; then _hit=true fi fi if $_hit ; then if [ "$_msg" = "error" ] ; then echo "ERROR: $_size consecutive failures for $_service_name, marking node unhealthy" exit 1 else return 1 fi fi } ######################################################## ctdb_status_dir="$CTDB_VARDIR/status" ctdb_fail_dir="$CTDB_VARDIR/failcount" ctdb_setup_service_state_dir () { service_state_dir="$CTDB_VARDIR/state/${1:-${service_name}}" mkdir -p "$service_state_dir" || { echo "Error creating state dir \"$service_state_dir\"" exit 1 } } ######################################################## # Managed status history, for auto-start/stop ctdb_managed_dir="$CTDB_VARDIR/managed_history" _ctdb_managed_common () { _ctdb_managed_file="$ctdb_managed_dir/$service_name" } ctdb_service_managed () { _ctdb_managed_common mkdir -p "$ctdb_managed_dir" touch "$_ctdb_managed_file" } ctdb_service_unmanaged () { _ctdb_managed_common rm -f "$_ctdb_managed_file" } is_ctdb_previously_managed_service () { _ctdb_managed_common [ -f "$_ctdb_managed_file" ] } ######################################################## # Check and set status log_status_cat () { echo "node is \"$1\", \"${script_name}\" reports problem: $(cat $2)" } ctdb_checkstatus () { if [ -r "$ctdb_status_dir/$script_name/unhealthy" ] ; then log_status_cat "unhealthy" "$ctdb_status_dir/$script_name/unhealthy" return 1 elif [ -r "$ctdb_status_dir/$script_name/banned" ] ; then log_status_cat "banned" "$ctdb_status_dir/$script_name/banned" return 2 else return 0 fi } ctdb_setstatus () { d="$ctdb_status_dir/$script_name" case "$1" in unhealthy|banned) mkdir -p "$d" cat "$2" >"$d/$1" ;; *) for i in "banned" "unhealthy" ; do rm -f "$d/$i" done ;; esac } ################################################################## # Reconfigure a service on demand _ctdb_service_reconfigure_common () { _d="$ctdb_status_dir/${service_name}" mkdir -p "$_d" _ctdb_service_reconfigure_flag="$_d/reconfigure" } ctdb_service_needs_reconfigure () { _ctdb_service_reconfigure_common [ -e "$_ctdb_service_reconfigure_flag" ] } ctdb_service_set_reconfigure () { _ctdb_service_reconfigure_common >"$_ctdb_service_reconfigure_flag" } ctdb_service_unset_reconfigure () { _ctdb_service_reconfigure_common rm -f "$_ctdb_service_reconfigure_flag" } ctdb_service_reconfigure () { echo "Reconfiguring service \"${service_name}\"..." ctdb_service_unset_reconfigure service_reconfigure || return $? ctdb_counter_init } # Default service_reconfigure() function does nothing. service_reconfigure () { : } ctdb_reconfigure_try_lock () { _ctdb_service_reconfigure_common _lock="${_d}/reconfigure_lock" mkdir -p "${_lock%/*}" # dirname touch "$_lock" ( flock 0 # This is overkill but will work if we need to extend this to # allow certain events to run multiple times in parallel # (e.g. takeip) and write multiple PIDs to the file. read _locker_event if [ -n "$_locker_event" ] ; then while read _pid ; do if [ -n "$_pid" -a "$_pid" != $$ ] && \ kill -0 "$_pid" 2>/dev/null ; then exit 1 fi done fi printf "%s\n%s\n" "$event_name" $$ >"$_lock" exit 0 ) <"$_lock" } ctdb_replay_monitor_status () { echo "Replaying previous status for this script due to reconfigure..." # Leading colon (':') is missing in some versions... _out=$(ctdb scriptstatus -Y | grep -E "^:?monitor:${script_name}:") # Output looks like this: # :monitor:60.nfs:1:ERROR:1314764004.030861:1314764004.035514:foo bar: # This is the cheapest way of getting fields in the middle. set -- $(IFS=":" ; echo $_out) _code="$3" _status="$4" # The error output field can include colons so we'll try to # preserve them. The weak checking at the beginning tries to make # this work for both broken (no leading ':') and fixed output. _out="${_out%:}" _err_out="${_out#*monitor:${script_name}:*:*:*:*:}" case "$_status" in OK) : ;; # Do nothing special. TIMEDOUT) # Recast this as an error, since we can't exit with the # correct negative number. _code=1 _err_out="[Replay of TIMEDOUT scriptstatus - note incorrect return code.] ${_err_out}" ;; DISABLED) # Recast this as an OK, since we can't exit with the # correct negative number. _code=0 _err_out="[Replay of DISABLED scriptstatus - note incorrect return code.] ${_err_out}" ;; *) : ;; # Must be ERROR, do nothing special. esac if [ -n "$_err_out" ] ; then echo "$_err_out" fi exit $_code } ctdb_service_check_reconfigure () { assert_service_name # We only care about some events in this function. For others we # return now. case "$event_name" in monitor|ipreallocated|reconfigure) : ;; *) return 0 ;; esac if ctdb_reconfigure_try_lock ; then # No events covered by this function are running, so proceed # with gay abandon. case "$event_name" in reconfigure) (ctdb_service_reconfigure) exit $? ;; ipreallocated) if ctdb_service_needs_reconfigure ; then ctdb_service_reconfigure fi ;; monitor) if ctdb_service_needs_reconfigure ; then ctdb_service_reconfigure # Given that the reconfigure might not have # resulted in the service being stable yet, we # replay the previous status since that's the best # information we have. ctdb_replay_monitor_status fi ;; esac else # Somebody else is running an event we don't want to collide # with. We proceed with caution. case "$event_name" in reconfigure) # Tell whoever called us to retry. exit 2 ;; ipreallocated) # Defer any scheduled reconfigure and just run the # rest of the ipreallocated event, as per the # eventscript. There's an assumption here that the # event doesn't depend on any scheduled reconfigure. # This is true in the current code. return 0 ;; monitor) # There is most likely a reconfigure in progress so # the service is possibly unstable. As above, we # defer any scheduled reconfigured. We also replay # the previous monitor status since that's the best # information we have. ctdb_replay_monitor_status ;; esac fi } ################################################################## # Does CTDB manage this service? - and associated auto-start/stop ctdb_compat_managed_service () { if [ "$1" = "yes" -a "$2" = "$service_name" ] ; then CTDB_MANAGED_SERVICES="$CTDB_MANAGED_SERVICES $2" fi } is_ctdb_managed_service () { assert_service_name # $t is used just for readability and to allow better accurate # matching via leading/trailing spaces t=" $CTDB_MANAGED_SERVICES " # Return 0 if "$service_name" appears in $t if [ "${t#* ${service_name} }" != "${t}" ] ; then return 0 fi # If above didn't match then update $CTDB_MANAGED_SERVICES for # backward compatibility and try again. ctdb_compat_managed_service "$CTDB_MANAGES_VSFTPD" "vsftpd" ctdb_compat_managed_service "$CTDB_MANAGES_SAMBA" "samba" ctdb_compat_managed_service "$CTDB_MANAGES_WINBIND" "winbind" ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD" "apache2" ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD" "httpd" ctdb_compat_managed_service "$CTDB_MANAGES_ISCSI" "iscsi" ctdb_compat_managed_service "$CTDB_MANAGES_CLAMD" "clamd" ctdb_compat_managed_service "$CTDB_MANAGES_NFS" "nfs" ctdb_compat_managed_service "$CTDB_MANAGES_NFS" "nfs-ganesha-gpfs" t=" $CTDB_MANAGED_SERVICES " # Return 0 if "$service_name" appears in $t [ "${t#* ${service_name} }" != "${t}" ] } ctdb_start_stop_service () { assert_service_name # Allow service-start/service-stop pseudo-events to start/stop # services when we're not auto-starting/stopping and we're not # monitoring. case "$event_name" in service-start) if is_ctdb_managed_service ; then die 'service-start event not permitted when service is managed' fi if [ "$CTDB_SERVICE_AUTOSTARTSTOP" = "yes" ] ; then die 'service-start event not permitted with $CTDB_SERVICE_AUTOSTARTSTOP = yes' fi ctdb_service_start exit $? ;; service-stop) if is_ctdb_managed_service ; then die 'service-stop event not permitted when service is managed' fi if [ "$CTDB_SERVICE_AUTOSTARTSTOP" = "yes" ] ; then die 'service-stop event not permitted with $CTDB_SERVICE_AUTOSTARTSTOP = yes' fi ctdb_service_stop exit $? ;; esac # Do nothing unless configured to... [ "$CTDB_SERVICE_AUTOSTARTSTOP" = "yes" ] || return 0 [ "$event_name" = "monitor" ] || return 0 if is_ctdb_managed_service ; then if ! is_ctdb_previously_managed_service ; then echo "Starting service \"$service_name\" - now managed" background_with_logging ctdb_service_start exit $? fi else if is_ctdb_previously_managed_service ; then echo "Stopping service \"$service_name\" - no longer managed" background_with_logging ctdb_service_stop exit $? fi fi } ctdb_service_start () { # The service is marked managed if we've ever tried to start it. ctdb_service_managed service_start || return $? ctdb_counter_init ctdb_check_tcp_init } ctdb_service_stop () { ctdb_service_unmanaged service_stop } # Default service_start() and service_stop() functions. # These may be overridden in an eventscript. When overriding, the # following convention must be followed. If these functions are # called with no arguments then they may use internal logic to # determine whether the service is managed and, therefore, whether # they should take any action. However, if the service name is # specified as an argument then an attempt must be made to start or # stop the service. This is because the auto-start/stop code calls # them with the service name as an argument. service_start () { service "$service_name" start } service_stop () { service "$service_name" stop } ################################################################## ctdb_standard_event_handler () { case "$1" in status) ctdb_checkstatus exit ;; setstatus) shift ctdb_setstatus "$@" exit ;; esac } # iptables doesn't like being re-entered, so flock-wrap it. iptables() { flock -w 30 $CTDB_VARDIR/iptables-ctdb.flock /sbin/iptables "$@" } # AIX (and perhaps others?) doesn't have mktemp if ! which mktemp >/dev/null 2>&1 ; then mktemp () { _dir=false if [ "$1" = "-d" ] ; then _dir=true shift fi _d="${TMPDIR:-/tmp}" _hex10=$(dd if=/dev/urandom count=20 2>/dev/null | \ md5sum | \ sed -e 's@\(..........\).*@\1@') _t="${_d}/tmp.${_hex10}" ( umask 077 if $_dir ; then mkdir "$_t" else >"$_t" fi ) echo "$_t" } fi ######################################################## # tickle handling ######################################################## update_tickles () { _port="$1" tickledir="$CTDB_VARDIR/state/tickles" mkdir -p "$tickledir" # Who am I? _pnn=$(ctdb pnn) ; _pnn=${_pnn#PNN:} # What public IPs do I hold? _ips=$(ctdb -Y ip | awk -F: -v pnn=$_pnn '$3 == pnn {print $2}') # IPs as a regexp choice _ipschoice="($(echo $_ips | sed -e 's/ /|/g' -e 's/\./\\\\./g'))" # Record connections to our public IPs in a temporary file _my_connections="${tickledir}/${_port}.connections" rm -f "$_my_connections" netstat -tn | awk -v destpat="^${_ipschoice}:${_port}\$" \ '$1 == "tcp" && $6 == "ESTABLISHED" && $4 ~ destpat {print $5, $4}' | sort >"$_my_connections" # Record our current tickles in a temporary file _my_tickles="${tickledir}/${_port}.tickles" rm -f "$_my_tickles" for _i in $_ips ; do ctdb -Y gettickles $_i $_port | awk -F: 'NR > 1 { printf "%s:%s %s:%s\n", $2, $3, $4, $5 }' done | sort >"$_my_tickles" # Add tickles for connections that we haven't already got tickles for comm -23 "$_my_connections" "$_my_tickles" | while read _src _dst ; do ctdb addtickle $_src $_dst done # Remove tickles for connections that are no longer there comm -13 "$_my_connections" "$_my_tickles" | while read _src _dst ; do ctdb deltickle $_src $_dst done rm -f "$_my_connections" "$_my_tickles" } ######################################################## # load a site local config file ######################################################## [ -n "$CTDB_RC_LOCAL" -a -x "$CTDB_RC_LOCAL" ] && { . "$CTDB_RC_LOCAL" } [ -x $CTDB_BASE/rc.local ] && { . $CTDB_BASE/rc.local } [ -d $CTDB_BASE/rc.local.d ] && { for i in $CTDB_BASE/rc.local.d/* ; do [ -x "$i" ] && . "$i" done } script_name="${0##*/}" # basename service_fail_limit=1 event_name="$1" ctdb-2.5.1.dfsg/config/ctdb-crash-cleanup.sh0000755000175000017500000000133312245023514020470 0ustar mathieumathieu#!/bin/sh # # This script can be called from a cronjob to automatically drop/release # all public ip addresses if CTDBD has crashed or stopped running. # [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; echo "$PWD") . "$CTDB_BASE/functions" # If ctdb is running, just exit if service ctdb status >/dev/null 2>&1 ; then exit 0 fi loadconfig ctdb [ -n "$CTDB_PUBLIC_ADDRESSES" ] || \ CTDB_PUBLIC_ADDRESSES="$CTDB_BASE/public_addresses" [ -f "$CTDB_PUBLIC_ADDRESSES" ] || \ die "No public addresses file found. Can't clean up." drop_all_public_ips 2>&1 | script_log "ctdb-crash-cleanup.sh" if [ -n "$CTDB_NATGW_PUBLIC_IP" ] ; then drop_ip "$CTDB_NATGW_PUBLIC_IP" "ctdb-crash-cleanup.sh" fi ctdb-2.5.1.dfsg/config/debug_locks.sh0000755000175000017500000000401712245023514017314 0ustar mathieumathieu#!/bin/sh # This script parses /proc/locks and finds the processes that are holding # locks on CTDB databases. For all those processes the script dumps a # stack trace using gstack. # # This script can be used only if Samba is configured to use fcntl locks # rather than mutex locks. [ -n "$CTDB_BASE" ] || \ export CTDB_BASE=$(cd -P $(dirname "$0") ; echo "$PWD") . "$CTDB_BASE/functions" # Default fallback location for database directories. # These can be overwritten from CTDB configuration CTDB_DBDIR="${CTDB_VARDIR}" CTDB_DBDIR_PERSISTENT="${CTDB_VARDIR}/persistent" loadconfig ctdb ( flock -n 9 || exit 1 echo "===== Start of debug locks PID=$$ =====" # Create sed expression to convert inodes to names sed_cmd=$( ls -li "$CTDB_DBDIR"/*.tdb.* "$CTDB_DBDIR_PERSISTENT"/*.tdb.* | sed -e "s#${CTDB_DBDIR}/\(.*\)#\1#" \ -e "s#${CTDB_DBDIR_PERSISTENT}/\(.*\)#\1#" | awk '{printf "s#[0-9]*:[0-9]*:%s #%s #\n", $1, $10}' ) # Parse /proc/locks and extract following information # pid process_name tdb_name offsets [W] out=$( cat /proc/locks | grep -F "POSIX ADVISORY WRITE" | awk '{ if($2 == "->") { print $6, $7, $8, $9, "W" } else { print $5, $6, $7, $8 } }' | while read pid rest ; do pname=$(readlink /proc/$pid/exe) echo $pid $pname $rest done | sed -e "$sed_cmd" | grep "\.tdb" ) if [ -n "$out" ]; then # Log information about locks echo "$out" # Find processes that are waiting for locks dbs=$(echo "$out" | grep "W$" | awk '{print $3}') all_pids="" for db in $dbs ; do pids=$(echo "$out" | grep -v "W$" | grep "$db" | grep -v ctdbd | awk '{print $1}') all_pids="$all_pids $pids" done pids=$(echo $all_pids | tr " " "\n" | sort -u) # For each process waiting, log stack trace for pid in $pids ; do echo "----- Stack trace for PID=$pid -----" gstack $pid # gcore -o /var/log/core-deadlock-ctdb $pid done fi echo "===== End of debug locks PID=$$ =====" ) 9>"${CTDB_VARDIR}/debug_locks.lock" | script_log "ctdbd-lock" exit 0 ctdb-2.5.1.dfsg/config/ctdb.sudoers0000644000175000017500000000014412245023514017013 0ustar mathieumathieuDefaults!/etc/ctdb/statd-callout !requiretty rpcuser ALL=(ALL) NOPASSWD: /etc/ctdb/statd-callout ctdb-2.5.1.dfsg/web/0000755000175000017500000000000012245023514014002 5ustar mathieumathieuctdb-2.5.1.dfsg/web/building.html0000644000175000017500000000173012245023514016466 0ustar mathieumathieu

Building CTDB and Samba

CTDB

To build a copy of CTDB code from a git tree you should do this:
   cd ctdb
   ./autogen.sh
   ./configure
   make
   make install
To build a copy of CTDB code from a tarball you should do this:
   tar xf ctdb-x.y.tar.gz
   cd ctdb-x.y
   ./configure
   make
   make install
You need to install ctdb on all nodes of your cluster.

Samba3

To build a copy of Samba3 with clustering and ctdb support you should do this:
    cd samba_3_0_ctdb/source
    ./autogen.sh
    ./configure --with-ctdb=/usr/src/ctdb --with-cluster-support --enable-pie=no
    make proto
    make
Once compiled, you should install Samba on all cluster nodes.

The /usr/src/ctdb path should be replaced with the path to the ctdb sources that you downloaded above. ctdb-2.5.1.dfsg/web/footer.html0000644000175000017500000000313012245023514016163 0ustar mathieumathieu
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Google
 
Search WWW Search samba.org
ctdb-2.5.1.dfsg/web/ftp.html0000644000175000017500000000577512245023514015477 0ustar mathieumathieu

Setting up clustered FTP

Prereqs

Configure CTDB as above and set it up to use public ipaddresses.
Verify that the CTDB cluster works.

Configuration

Setting up a vsftpd cluster is really easy.
Configure vsftpd on each node on the cluster.

Set up vsftpd to export directories from the shared cluster filesystem.

/etc/sysconfig/ctdb

Add the following line to the /etc/sysconfig/ctdb configuration file.
  CTDB_MANAGES_VSFTPD=yes
Disable vsftpd in chkconfig so that it does not start by default. Instead CTDB will start/stop vsftdp as required.
  chkconfig vsftpd off

PAM configuration

PAM must be configured to allow authentication of CIFS users so that the ftp daemon can authenticate the users logging in. Make sure the following line is present in /etc/pam.d/system-auth
auth        sufficient    pam_winbind.so use_first_pass

If this line is missing you must enable winbind authentication by running
authconfig  --enablewinbindauth --update
authconfig  --enablewinbind --update

Default shell

To log in to the ftp server, the user must have a shell configured in smb.conf. Add the following line to the globals section of /etc/samba/smb.conf
	template shell = /bin/bash

Home directory

FTP users must have a home directory configured so they can log in. Configure samba to provide home directories for domain users. These home directories should be stored on shared storage so they are available from all nodes in the cluster.
A simple way to create homedirectories are to add
	template homedir = /<shared storage>/homedir/%D/%U
to /etc/samba/smb.conf .
The homedirectory must exist or the user will not be able to log in with FTP.

Events script

The CTDB distribution already comes with an events script for vsftp in the file /etc/ctdb/events.d/40.vsftpd

There should not be any need to edit this file.

Restart your cluster

Next time your cluster restarts, CTDB will start managing the vsftp service.

If the cluster is already in production you may not want to restart the entire cluster since this would disrupt services.
Insted you can just disable/enable the nodes one by one. Once a node becomes enabled again it will start the vsftp service.

Follow the procedure below for each node, one node at a time :

1 Disable the node

Use the ctdb command to disable the node :
  ctdb -n NODE disable

2 Wait until the cluster has recovered

Use the ctdb tool to monitor until the cluster has recovered, i.e. Recovery mode is NORMAL. This should happen within seconds of when you disabled the node.
  ctdb status

3 Enable the node again

Re-enable the node again which will start the newly configured vsftp service.
  ctdb -n NODE enable
ctdb-2.5.1.dfsg/web/download.html0000644000175000017500000000254212245023514016502 0ustar mathieumathieu

Getting the code

You need two source trees, one is a copy of Samba3 and the other is the ctdb code itself.

Both source trees are stored in git repositories.

CTDB

You can download ctdb source code via ftp and http.

You can also get the latest development version of ctdb using git:
   git clone git://git.samba.org/ctdb.git ctdb
To update this tree when improvements are made in the upstream code do this:
    cd ctdb
    git pull
If you don't have git and can't easily install it, then you can instead use the following command to fetch ctdb or update it:
    rsync -avz samba.org::ftp/unpacked/ctdb .

Samba3 ctdb version

With Samba version 3.3 all cluster-relevant changes have been merged to the mainstream Samba code. Please refer to the Samba website for the current release information.

Binary Packages

Note that packages are so far only available for RHEL5. Other packages may come later.

See packages directory for package downloads. ctdb-2.5.1.dfsg/web/configuring.html0000644000175000017500000001524112245023514017205 0ustar mathieumathieu

Configuring CTDB

Clustering Model

The setup instructions on this page are modelled on setting up a cluster of N nodes that function in nearly all respects as a single multi-homed node. So the cluster will export N IP interfaces, each of which is equivalent (same shares) and which offers coherent CIFS file access across all nodes.

The clustering model utilizes IP takeover techniques to ensure that the full set of public IP addresses assigned to services on the cluster will always be available to the clients even when some nodes have failed and become unavailable.

CTDB Cluster Configuration

These are the primary configuration files for CTDB.

When CTDB is installed, it will install template versions of these files which you need to edit to suit your system.

/etc/sysconfig/ctdb

This file contains the startup parameters for ctdb.

When you installed ctdb, a template config file should have been installed in /etc/sysconfig/ctdb.

Edit this file, following the instructions in the template.

The most important options are:

  • CTDB_NODES
  • CTDB_RECOVERY_LOCK
  • CTDB_PUBLIC_ADDRESSES
Please verify these parameters carefully.

CTDB_RECOVERY_LOCK

This parameter specifies the lock file that the CTDB daemons use to arbitrate which node is acting as a recovery master.
This file MUST be held on shared storage so that all CTDB daemons in the cluster will access/lock the same file.

You must specify this parameter.
There is no default for this parameter.

CTDB_NODES

This file needs to be created and should contain a list of the private IP addresses that the CTDB daemons will use in your cluster. One IP address for each node in the cluster.

This should be a private non-routable subnet which is only used for internal cluster traffic. This file must be the same on all nodes in the cluster.

Make sure that these IP addresses are automatically started when the cluster node boots and that each node can ping each other node.

Example 4 node cluster:

  CTDB_NODES=/etc/ctdb/nodes
Content of /etc/ctdb/nodes:
 10.1.1.1
 10.1.1.2
 10.1.1.3
 10.1.1.4
The default for this file is /etc/ctdb/nodes.

CTDB_PUBLIC_ADDRESSES

Each node in a CTDB cluster contains a list of public addresses which that particular node can host.

While running the CTDB cluster will assign each public address that exists in the entire cluster to one node that will host that public address.

These are the addresses that the SMBD daemons and other services will bind to and which clients will use to connect to the cluster.

Example 4 node cluster:

  CTDB_PUBLIC_ADDRESSES=/etc/ctdb/public_addresses
Content of /etc/ctdb/public_addresses:
 192.168.1.1/24 eth0
 192.168.1.2/24 eth0
 192.168.2.1/24 eth1
 192.168.2.2/24 eth1
These are the IP addresses that you should configure in DNS for the name of the clustered samba server and are the addresses that CIFS clients will connect to.

Configure it as one DNS A record (==name) with multiple IP addresses and let round-robin DNS distribute the clients across the nodes of the cluster.

The CTDB cluster utilizes IP takeover techniques to ensure that as long as at least one node in the cluster is available, all the public IP addresses will always be available to clients.

This means that if one physical node fails, the public addresses that node was serving will be taken over by a different node in the cluster. This provides a guarantee that all ip addresses exposed to clients will always be reachable by clients as long as at least one node still remains available in the cluster with the capability to host that public address (i.e. the public address exists in that nodes public_addresses file). Do not assign these addresses to any of the interfaces on the host. CTDB will add and remove these addresses automatically at runtime.

This parameter is used when CTDB operated in takeover ip mode.

The usual location for this file is /etc/ctdb/public_addresses.

Example 2:

By using different public_addresses files on different nodes it is possible to partition the cluster into subsets of nodes.
Node 0 : /etc/ctdb/public_addresses
10.1.1.1/24 eth0
10.1.2.1/24 eth1
Node 1 : /etc/ctdb/public_addresses
10.1.2.1/24 eth1
10.1.3.1/24 eth2
Node 2 : /etc/ctdb/public_addresses
10.1.3.2/24 eth2
In this example we have three nodes but a total of 4 public addresses.

10.1.2.1 can be hosted by either node 0 or node 1 and will be available to clients as long as at least one of these nodes are available. Only if both nodes 0 and 1 fails will this public address become unavailable to clients.

All other public addresses can only be served by one single node respectively and will therefore only be avialable if the respective node is also available.

Event scripts

CTDB comes with a number of application specific event scripts that are used to do service specific tasks when the cluster has been reconfigured. These scripts are stored in /etc/ctdb/events.d/

You do not need to modify these scripts if you just want to use clustered Samba or NFS but they serve as examples in case you want to add clustering support for other application servers we do not yet proivide event scripts for.

Please see the service scripts that installed by ctdb in /etc/ctdb/events.d for examples of how to configure other services to be aware of the HA features of CTDB.

Also see /etc/ctdb/events.d/README for additional documentation on how to create and manage event scripts.

TCP port to use for CTDB

CTDB defaults to use TCP port 4379 for its traffic.

Configuring a different port to use for CTDB traffic is done by adding a ctdb entry to the /etc/services file.

Example: for change CTDB to use port 9999 add the following line to /etc/services

 ctdb  9999/tcp
Note: all nodes in the cluster MUST use the same port or else CTDB will not start correctly.

Name resolution

You need to setup some method for your Windows and NFS clients to find the nodes of the cluster, and automatically balance the load between the nodes.

We recommend that you use public ip addresses using CTDB_PUBLIC_INTERFACE/CTDB_PUBLIC_ADDRESSES and that you setup a round-robin DNS entry for your cluster, listing all the public IP addresses that CTDB will be managing as a single DNS A record.

You may also wish to setup a static WINS server entry listing all of your cluster nodes IP addresses. ctdb-2.5.1.dfsg/web/nfs.html0000644000175000017500000000656412245023514015471 0ustar mathieumathieu

Setting up clustered NFS

NFS v2/v3 has been successfully tested with exporting the same data/network share from multiple nodes in a CTDB cluster with correct file locking behaviour and lock recovery.

Also see Configuring NFS for CTDB clustering at samba.org for additional information.

Prereqs

Configure CTDB as above and set it up to use public ipaddresses.
Verify that the CTDB cluster works.

/etc/exports

Export the same directory from all nodes.
Make sure to specify the fsid export option so that all nodes will present the same fsid to clients.
Clients can get "upset" if the fsid on a mount suddenly changes.
Example /etc/exports :
  /gpfs0/data *(rw,fsid=1235)

/etc/sysconfig/nfs

This file must be edited to point statd to keep its state directory on shared storage instead of in a local directory.

We must also make statd use a fixed port to listen on that is the same for all nodes in the cluster.
If we don't specify a fixed port, the statd port will change during failover which causes problems on some clients.
(some clients are very slow to realize when the port has changed)

This file should look something like :
  NFS_HOSTNAME=ctdb
  STATD_PORT=595
  STATD_OUTGOING_PORT=596
  MOUNTD_PORT=597
  RQUOTAD_PORT=598
  LOCKD_TCPPORT=599
  LOCKD_UDPPORT=599
  STATD_HOSTNAME="$NFS_HOSTNAME -H /etc/ctdb/statd-callout -p 97"
  RPCNFSDARGS="-N 4"

You need to make sure that the lock manager runs on the same port on all nodes in the cluster since some clients will have "issues" and take very long to recover if the port suddenly changes.
599 above is only an example. You can run the lock manager on any available port as long as you use the same port on all nodes.

NFS_HOSTNAME is the dns name for the ctdb cluster and which is used when clients map nfs shares. This name must be in DNS and resolve back into the public ip addresses of the cluster.
Always use the same name here as you use for the samba hostname. RPCNFSDARGS is used to disable support for NFSv4 which is not yet supported by CTDB.

/etc/sysconfig/ctdb

Add the following line to /etc/sysconfig/ctdb :
  CTDB_MANAGES_NFS=yes
The CTDB_MANAGES_NFS line tells the events scripts that CTDB is to manage startup and shutdown of the NFS and NFSLOCK services.
With this set to yes, CTDB will start/stop/restart these services as required.

chkconfig

Since CTDB will manage and start/stop/restart the nfs and the nfslock services, you must disable them using chkconfig.
  chkconfig nfs off
  chkconfig nfslock off

Event scripts

CTDB clustering for NFS relies on two event scripts /etc/ctdb/events.d/60.nfs and /etc/ctdb/events.d/61.nfstickle.
These two scripts are provided by the RPM package and there should not be any need to change them.

IMPORTANT

Never ever mount the same nfs share on a client from two different nodes in the cluster at the same time!

The client side caching in NFS is very fragile and assumes/relies on that an object can only be accessed through one single path at a time. ctdb-2.5.1.dfsg/web/index.html0000644000175000017500000001321412245023514016000 0ustar mathieumathieu

Welcome to the CTDB web pages

CTDB is a cluster implementation of the TDB database used by Samba and other projects to store temporary data. If an application is already using TDB for temporary data it is very easy to convert that application to be cluster aware and use CTDB instead.

CTDB provides the same types of functions as TDB but in a clustered fashion, providing a TDB-style database that spans multiple physical hosts in a cluster.

Features include:

  • CTDB provides a TDB that has consistent data and consistent locking across all nodes in a cluster.
  • CTDB is very fast.
  • In case of node failures, CTDB will automatically recover and repair all TDB databases that it manages.
  • CTDB is the core component that provides pCIFS ("parallel CIFS") with Samba3/4.
  • CTDB provides HA features such as node monitoring, node failover, and IP takeover.
  • CTDB provides a reliable messaging transport to allow applications linked with CTDB to communicate to other instances of the application running on different nodes in the cluster.
  • CTDB has pluggable transport backends. Currently implemented backends are TCP and Infiniband.
  • CTDB supports a system of application specific management scripts, allowing applications that depend on network or filesystem resources to be managed in a highly available manner on a cluster.

Requirements

CTDB relies on a clustered filesystem being available and shared on all nodes that participate in the CTDB cluster. This filesystem must be mounted and available on all nodes in the CTDB cluster.

On top of this cluster filesystem, CTDB then provides clustered HA features so that data from the clustered filesystem can be exported through multiple nodes in the CTDB cluster using various services. Currently included with CTDB are the necessary hooks for Samba, NFS and ftp exports. Support for new service types can easily be added.

TDB

TDB is a very fast simple database that was originally developed for use in Samba. Today several other projects use TDB to store their data.

See the TDB README file for a description of how TDB is used.

Documentation

CTDB documentation

Additional documentation on how to install and configure CTDB is available in the CTDB Wiki. Please read all of the documentation carefully.

High Availability Features

The CTDB nodes in a cluster designates one node as a recovery master through an election process. If the recovery master node fails a new election is initiated so that the cluster will always guarantee there will be a recovery master. The recovery master will continuously monitor the cluster to verify that all nodes contain a consistent configuration and view of the cluster and will initiate a recovery process when required.

During the recovery phase, the recovery master will automatically rebuild/recover all clustered TDB database to ensure that the databases are consistent. Recovery typically takes between 1 and 3 seconds. During the recovery period the databases are 'frozen', and all database IO operations by ctdb clients are suspended.

Is CTDB a HA solution?

Yes and no.

CTDB alone is not a HA solution, but when you combine CTDB with a clustered filesystem it becomes one.

CTDB is primarily developed around the concept of having a shared cluster filesystem across all the nodes in the cluster to provide the features required for building a NAS cluster.

Thus CTDB relies on an external component (the cluster filesystem) to provide the mechanisms for avoiding split-brain and other core clustering tasks.

However, if you do have a clustered filesystem for all the nodes, in that scenario CTDB will provide a very easy to install and manage solution for your clustering HA needs.

IP Takeover

When a node in a cluster fails, CTDB will arrange that a different node takes over the IP address of the failed node to ensure that the IP addresses for the services provided are always available.

To speed up the process of IP takeover and when clients attached to a failed node recovers as fast as possible, CTDB will automatically generate gratuitous ARP packets to inform all nodes of the changed MAC address for that IP. CTDB will also send "tickle ACK" packets to all attached clients to trigger the clients to immediately recognize that the TCP connection needs to be re-established and to shortcut any TCP retransmission timeouts that may be active in the clients.

Discussion and bug reports

For discussions please use the samba-technical mailing list. To submit a bug report, please use the Samba bugzilla bug tracking system.

We would be very interested in hearing from and work with other projects that want to make their services cluster aware using CTDB.

CTDB discussions also happen on the #ctdb IRC channel on freenode.net


Developers

ctdb-2.5.1.dfsg/web/samba.html0000644000175000017500000000615112245023514015756 0ustar mathieumathieu

Setting up clustered samba

It is assumed tou have already installed the ctdb version of samba and also installed, configured and tested CTDB.

Create a user account

First you need to initialise the Samba password database so that you have some user that can authenticate to the samba service.
Do this by running:
  smbpasswd -a root
Samba with clustering must use the tdbsam or ldap SAM passdb backends (it must not use the default smbpasswd backend), or must be configured to be a member of a domain.
The rest of the configuration of Samba is exactly as it is done on a normal system.

See the docs on http://samba.org/ for details.

Critical smb.conf parameters

A clustered Samba install must set some specific configuration parameters
  clustering = yes
  idmap backend = tdb2

Using smbcontrol

You can check for connectivity to the smbd daemons on each node using smbcontrol
  smbcontrol smbd ping

Using Samba4 smbtorture

The Samba4 version of smbtorture has several tests that can be used to benchmark a CIFS cluster. You can download Samba 4 from Samba website. The particular tests that are helpful for cluster benchmarking are the RAW-BENCH-OPEN, RAW-BENCH-LOCK and BENCH-NBENCH tests.
These tests take a unclist that allows you to spread the workload out over more than one node. For example:
  smbtorture //localhost/data -Uuser%password  RAW-BENCH-LOCK --unclist=unclist.txt --num-progs=32 -t60
The file unclist.txt should contain a list of server names in your cluster prefixed by //. For example
 //192.168.1.1
 //192.168.1.2
 //192.168.2.1
 //192.168.2.2
For NBENCH testing you need a client.txt file.
A suitable file can be found in the dbench distribution at http://samba.org/ftp/tridge/dbench/

CTDB_MANAGES_SAMBA

This is a parameter in /etc/sysconfig/ctdb

When this parameter is set to "yes" CTDB will start/stop/restart the local samba daemon as the cluster configuration changes.

When this parameter is set you should also make sure that samba is NOT started by default by the linux system when it boots, e.g.
  chkconfig smb off
on a Redhat system and
  chkconfig smb off
  chkconfig nmb off
on a SuSE system. Example:
  CTDB_MANAGES_SAMBA="yes"
It is strongly recommended that you set this parameter to "yes" if you intend to use clustered samba.

CTDB_MANAGES_WINBIND

This is a parameter in /etc/sysconfig/ctdb

When this parameter is set to "yes" CTDB will start/stop/restart the local winbind daemon as the cluster configuration changes.

When this parameter is set you should also make sure that winbind is NOT started by default by the linux system when it boots:
  chkconfig winbind off
Example:
  CTDB_MANAGES_WINBIND="yes"
It is strongly recommended that you set this parameter to "yes" if you intend to use clustered samba in DOMAIN or ADS security mode. ctdb-2.5.1.dfsg/web/prerequisites.html0000644000175000017500000000175712245023514017606 0ustar mathieumathieu

Prerequisites

Before you can start using CTDB you must first install and configure a bunch of linux boxes.

After that you need to install and configure a cluster filesystem and mount that cluster filesystem on all the linux boxes that will form your cluster.

Also, ensure that the cluster filesystem supports correct posix locking semantics. A simple way to test this is to run ping_pong utility bundled with CTDB.

Cluster filesystems

We have primarily used the GPFS filesystem for our testing but any cluster filesystem should work as long as it provides correct file locking.

While we primarily test with GPFS, CTDB should work with almost any other cluster filesystem as well.

Please let us know your experiences in using other cluster filesystems. ctdb-2.5.1.dfsg/web/header.html0000644000175000017500000000255112245023514016123 0ustar mathieumathieu <!--#echo var="TITLE" -->
CTDB
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ctdb-2.5.1.dfsg/web/iscsi.html0000644000175000017500000000675312245023514016015 0ustar mathieumathieu

Setting up HA iSCSI with CTDB

You can use CTDB to create a HA iSCSI Target.

Since the iSCSI Target is not clusterized nor integrated with CTDB in the same sense Samba is, this implementation will only create a HA solution for iSCSI where each public address is assinged its own iscsi target name and the LUNs that are created are only accessible through one specific target (i.e. one public address at a time).

! This feature ONLY works when public addresses are used. It is not supported, nor does it work, if you use the LVS feature to present the entire cluster as one single ip address. !

Prereqs

Configure CTDB as above and set it up to use public ipaddresses.
Verify that the CTDB cluster works.

Install the iSCSI target software on all nodes

On RHEL5 this package is called "scsi-target-utils" and it needs to be installed on all nodes in the cluster. The easiest way to install this package is by using :
onnode all yum install scsi-target-utils -y
Make sure that the service is not started automatically when booting, we want CTDB to start/stop this service :
onnode all chkconfig tgtd off

/etc/sysconfig/iscsi

Create this file and add the following three lines to it :
   CTDB_START_ISCSI_SCRIPTS=/gpfs/iscsi/

CTDB_START_ISCSI_SCRIPTS= This is a directory on shared storage where the scripts to start and configure the iscsi service are held. There is one script for each public address named .sh .

/etc/sysconfig/ctdb

Add the following line to /etc/sysconfig/ctdb :
   CTDB_MANAGES_ISCSI=yes

CTDB_MANAGES_ISCSI=yes just tells CTDB event script for iSCSI that CTDB should start and stop the iSCSI target service as required.

Example: create a LUN that will be hosted on public ip address 10.1.1.1

Before you cna export a LUN you must create it as a file in the shared filesystem. When doing so, make sure you create it as a real file and not a sparse file!
While it is much quicker to create a sparse file if you want a file with filesize 100Gb, SCSI has no concept of "disk full" so if you run out of backing space for the sparse file, the scsi initiators will be "surprised" and "unhappy".

dd if=/dev/zero of=/gpfs/iscsi/10.1.1.1.lun.1 bs=1024 count=102400

to create a 100MByte file to export as an iSCSI LUN.

Example: 10.1.1.1.sh

This example shellscript is used to configure the iscsi target that is hosted onthe public address 10.1.1.1

#!/bin/sh
# script to set up the iscsi target and luns hosted by public address
# 10.1.1.1


#create a target
tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.2007-11.com.ctdb:iscsi.target.10.1.1.1

#attach a lun
tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun 1 -b /gpfs/iscsi/10.1.1.1.lun.1

# no security, allow everyone to access this lun
tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL

iqn.2007-11.com.ctdb:iscsi.target.10.1.1.1 in the example above is the iscsi name that is assigned to the target. Dont use this name, pick your own name!

See the documentation for the tgtadm command for more information on how you want to set up your environment.

Perform a ctdb recovery to start the iscsi service

ctdb recover
ctdb-2.5.1.dfsg/web/ctdblogo.png0000644000175000017500000002364112245023514016313 0ustar mathieumathieuPNG  IHDR@T|y pHYs  tIME $dtEXtCommentCreated with The GIMPd%n IDATxw|VEƿ鄐FGBiJQ@@ۢ‚bYQYۊ좮65J@Hy-䕄Ax;weX&ð4^jƹ\G~m*[ګ-%fǹ"][q'4Ļ^7#2nIvŷo\Um@_Hp/ξ=no7:p܀(߂Zn+"eh{8܄rrgkIVMn7aU.F7 ˛P\qWq߯{NkVϐL?R2^^Ydf^09X>Ϗ}H` #?d \KC_!Y*]bw⤶ř} iG䏜N8i01"V(;pıΰȱFuMh湟 (k-oBcoB!,dԙڵY!:3y,$4U~eC6RU Co_ o{P(#ٷ,hny&q_´ԙvMnbK@ξxfFxT`h&3anLPP7Оqst{>mqAɁ_2|ónh7&^P< B3g*E`w&Ʀ瞒N*ߺf кuԈ~닯oT׼%y|}qgŋK+_o|}iٌa.զ%gь 8){۶i.Z\wJ?RdIج~ yW  sl^iΠIm=Gg BkYZőLT1e΢ts%~{! ݁4Pn$eS`H=lrKٴXBn=o2*\4 YjbcxzPN8:D/F /{U}700D: Qz-sz!kT4-]j|{of7ևjR{OR58 *L;Ᶎ>iA}5q/e؃ML||N14+LYrt{G*=:ב|5 E/=Sm[\, 1}zzځNQ'  P;d3|:j.Je4lCB͚isb7RvBnrC!!:u"piy"Ѳ932`:w̙rg(钨~voKdC:+1Z^rzuϫ;s<};חs?DhTS[_|V!av6;M]~)s++,qh@MZDt'! ڹS&k!,4APp,(aJ¤'0dC_?]U};.n:FJ}L[,+7)aÆ>c}}P.J͛sS4 Ug=F#@_={+O>q9#()IyO3u& %ӧ&JDu襗J-_yHȐ(uD;wʝ.{&L5拓^VfMi,`d^}@sX #w4]@ ċ{BKJj-o΢(,Lqqz:wd"seCѰaivuG)4Bᐤ)gTTS.^^zݒd5whl+jg&ny^a4 VRgiq1G}¹qm&Zro;^w2QŊJN| l_8GM!<3~{F GaC gE=xnXoJD*ȹ=Z PVO3P2G4zwd;7Ix%t&O|go7w=p*,,UasDŽ^Ll^P I/N~)<פQbdCQ6;'8@6{ˌÙ$I(KJˌQEԩo[M" xeF߆ؽE*Tv[ kh[6@~潬Rs5టsE JZ ܣ[l%Ǖ02 Zobp\f{KV|k*d(zbIrnͻo9gQٻ@QJO/1({3%ţ4}z]G~lhĈQcS^l<}ڃ+X0.ِ gk~ $wAw gC5o)G}߾aÕ7_""<_#iTfMMB R[ԩm$m+dC ?R+aY7&H4Irͯ_o`?4{|6MCGW-@Q=Trq5r6_I:.w+gbWKuH/Doy8c-;KYtdI*\ W|; n4n4P7u^u'0?ƞ}:.L$~1š4q{M"$ب3^A{Qt EF;PE4fLA"Ix|,JBh tJ) +mB* 忡W^L]蟼RP/zOcΖJAY& [zSqmkn:p~}nͨNxX%34iд1͏e# +{+V_qԨKоM!Nht_9 E <28oWBzwaRxɇ< K=x_Md&"%̙' d$dR};jλEn|箷Rll_a\'d0}ӆ YMUrvokR|o'}TW'$}tMsWj1ݻn)1-)敝̽PEЁm =l\24i/5n M3MWK;~:RiHC#QZY~~gGx1=Joc.9OLNZ"t=?.3];m(6?A'I+;΋\dH[L. ?d2\ihꀼP˖rJ|^s߶Uښ5GӼ9ASص̂OxUQӟxGi~aw33s:7ܢ| YC>?8cyYH.7;(|U߱j/~G6m)|0*V֭ddZuI}p P{I8l6ۢpV&f͸~zʕ)xEظH~O?QEಐڵABnFjբGW/Qwyy ^7V-ucR?b#F8bn:4>"SRF?oWfzu9wHI1-[*L@.v%JϞkuK-'$d @׮lY5&MbnS5j\N'`*u -X߀~/Y> DX)Ԛ[PO){[Pi׹cr)G 3 x2-XM Ye_Uꓚ'ӧ(ΧfT|COnLh ǵ G4=1p6ލ~/q[ ʾYSVE"?!C\?>nQA`qF8pƱ'Y{OJpsa̘ߣFu[2~Dd8Ӱ!#v10`p"+5*Ѹ>z<+a[y ` XMag?;|\ s%]C[DZOڂ# c|-oFۖ4nO]ܵa&۶qCTzJl`;4iR*"ة.[<G( ㉊!*q/'ks+ ^rYl +賩ě  "2Jɸ>s8q, vw0U+;yp|DŰpf"T)T/$by9t\p+xUǧ-^WURc.7OPPr-6&׷ 0^Hn+.Q\ύv÷']Z{G y *=`v ukgK UQa6I֚=uIXCrWAcW/Ίlz _l2eG9O`1GbyϏZ IWu[0š5 YMfyC['4Ȏ]OO֧sG6!/֜&K;B$_ڱ_}|AцjVO =%?4< oQS0\w z4V0v.hbVdCA(<\))Td9tCi҈3ۛ~lSPv7ӬRv8Ow~axJ%Q4 5hϛ۳w@QRduOߧU+>.BQY2wѣGwVڳh u ?O<|\ef^^ %//0QR;k Ξ1z l5!S_lb BC5xrG=c+pKBCM"1y.QÄ\G\qټrϵI[D yD}ptmlGfaϒ wK^kL9\]kP%~!=a \]i;~E?M&0w9vdCR FE ãcX5+-zTvǢd:XǎY#.'?ϣb^_Ssi| B)FPa_u|}ܹ,?qҨ~ÇF <0+붮Z8s{nXf_E\y)-@޸XϻUtrsyxK)7?s5`Cfo1aoۛh Yw M Ї*&5=aE; E:rH=j&뛰}@Z\ywU&=a$gdCX&mZA͚St6{0ca5.8}rDhs烖{jl\S˨kc:Z@ݺ]NahJ)ϡC[oLL?nzZUԨ{ 0/ twёG7(5D5&MPEcCPJEȾy W'ŠO_e=Q>4fͺl:gMWz9F.]JFr9)qΨj1oF}|]V!_Z*o;˼LhмyHLݡvgnF~~ڼW<2O׼Q G۶]Nj##B6 V.]gm 2KܱnEv+^Haxiq5z#k}Vxɩ]_%&7f4jUqjצS_<&ܧ HcK]ss37x ZWsHJ1i R#t7@,T¸q~˟b 6BthGzW ,PUQؽl K">T*TSÇR( Θk,lF_xCq(<ah?{m.·@:t(G4oy^ܯ rd{HN69r`4lHEEfg K<@gLr5fW:|~~sU,o~٘8n#zƔPlRAytWO#c.>_x1وkbJD_sܧmTp)eslj5tBvg_y}a9d>N[~#=]a}m!/QQDF42>8>33yf<.W|Nٛw}F |<;: r%G PvwGsOM+5:&d%VHF|e4ΡéY_{kt@ <ˣNS9[6c*t}I "E6䏪VUZ$~dT/5>fKG@ hB~~Zs[?U'_;ѷ P( ҙ3?ʹYvS6z>e+3˟GrE-V>QЗt睞p0nK=.3_Ý~}}U,_]0%λo>ڣ[l*gEGY (ѻ?ߏv9}@U`Krnx$!B>l_?P%ҷWըZchEEMe$x~J‘ʿf,Tjd%cO'ƾf́ NEss 5]b=3t-ק׊URuо`= 0>C^A6' :x]{dž-n,4k wчZ?$e" V:-{tLԪ ka6@m ݘ3'""p|GFejwNO^(7a [|AH\ׄ}hژb ҡjULae%Wt~\BSt.}I8 ` "Kwї]-vjLK %rP䖎? ƂYYSo.0u6X1nԉW^8W6v]~=@x )G `ڳ|IԆ.qg$fXE6mw0aU\]"Gn.6q#6m2AQ??Gvm~ņ DGFzN Bq= VFQBêhK RH"#??d#4-2h9! f*T.䗃Q6 YN>yi/ӥ ݺI֦,[87Z) _c#!ݓIyFz0{$4|8q;뮣Y?1IIl\;@ar[/6z,jq㍿a-[`᷅JiE` ,X`E` ,[`" ,[`" qL6IENDB`ctdb-2.5.1.dfsg/web/testing.html0000644000175000017500000000617412245023514016355 0ustar mathieumathieu

Starting and testing CTDB

The CTDB log is in /var/log/log.ctdb so look in this file if something did not start correctly.

You can ensure that ctdb is running on all nodes using

  onnode all service ctdb start
Verify that the CTDB daemon started properly. There should normally be at least 2 processes started for CTDB, one for the main daemon and one for the recovery daemon.
  onnode all pidof ctdbd
Once all CTDB nodes have started, verify that they are correctly talking to each other.

There should be one TCP connection from the private ip address on each node to TCP port 4379 on each of the other nodes in the cluster.

  onnode all netstat -tn | grep 4379

Automatically restarting CTDB

If you wish to cope with software faults in ctdb, or want ctdb to automatically restart when an administration kills it, then you may wish to add a cron entry for root like this:
 * * * * * /etc/init.d/ctdb cron > /dev/null 2>&1

Testing CTDB

Once your cluster is up and running, you may wish to know how to test that it is functioning correctly. The following tests may help with that

The ctdb tool

The ctdb package comes with a utility called ctdb that can be used to view the behaviour of the ctdb cluster.

If you run it with no options it will provide some terse usage information. The most commonly used commands are:

 ctdb status
 ctdb ip
 ctdb ping

ctdb status

The status command provides basic information about the cluster and the status of the nodes. when you run it you will get some output like:
Number of nodes:4
vnn:0 10.1.1.1       OK (THIS NODE)
vnn:1 10.1.1.2       OK
vnn:2 10.1.1.3       OK
vnn:3 10.1.1.4       OK
Generation:1362079228
Size:4
hash:0 lmaster:0
hash:1 lmaster:1
hash:2 lmaster:2
hash:3 lmaster:3
Recovery mode:NORMAL (0)
Recovery master:0
The important parts are in bold. This tells us that all 4 nodes are in a healthy state.

It also tells us that recovery mode is normal, which means that the cluster has finished a recovery and is running in a normal fully operational state.

Recovery state will briefly change to "RECOVERY" when there ahs been a node failure or something is wrong with the cluster.

If the cluster remains in RECOVERY state for very long (many seconds) there might be something wrong with the configuration. See /var/log/log.ctdb.

ctdb ip

This command prints the current status of the public ip addresses and which physical node is currently serving that ip.
Number of nodes:4
192.168.1.1         0
192.168.1.2         1
192.168.2.1         2
192.168.2.1         3

ctdb ping

this command tries to "ping" each of the CTDB daemons in the cluster.
  ctdb ping -n all

  response from 0 time=0.000050 sec  (13 clients)
  response from 1 time=0.000154 sec  (27 clients)
  response from 2 time=0.000114 sec  (17 clients)
  response from 3 time=0.000115 sec  (59 clients)
ctdb-2.5.1.dfsg/web/bar1.jpg0000644000175000017500000000504212245023514015332 0ustar mathieumathieuJFIFHHCreated with The GIMPC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"9!1A"Qaq2T$#3BRb ?JP)JP)J0Ԭ 3%+{qPRdy3˶rmi\FH؂Fڱ0i Xm;cAҸO\ymHvP-x&6 x22[_J?,NDQ4Z4ِ ?/Zg8D24n,oU!hhv ,zb | aURf{o{P[傋z0U?Igl:XXWp@  kWOFg\|P" [5s$0qFIUw$dqZ_>f"1Y! I޶XN14HaGRֱۃý"??X*,Y"!>~Eqx{ / @}шkW'9y".2x3hM m#2W:yZ#dkX 6ډ6$2Pgr5Zǽ\#o͔r;}x(dJjca9':[*$/bwsRa:pEmm"έt0V%Hߎ+FVbY eA]DŽCXbX˒7kl.om{orgy I}(1gA*7kb_ ?Raۓ޺:*I;T6#n{=L#Ld*Pkצq{+"s'c9mcE޷âr@$^~ ׸3$GaB\wo{Pr3@T,@Cc?*?0lɣPvw <pXovӹDHFQ`m8z٢`UG{:6fI`9c{~A`;}I2l[`LMsAWu: DdTڅ;TT粐&v{Nn>5j} V xmATR(C*>!Kac֯Pщy'Ko ߓUx_1yogZEz #/gSFTZů ĆOhH+vnmj`nAMAJQ -$ Eo*u 3+K1d$Eb7`ou Z_H9:}3eZ,p@#M*Q$̧V Uٚ@qP@w޼=G$J xѯk=l҂TX IXñ<SǨ5K)$_{ߵW()Ǐw*R6sP?n8Kը~"ʨC6&{\|UJ c#$Dv7I y6ꁮlLA:}DksAJQ -$ Eo*u 3+K1d$Eb7`oXd A#q<ʒ>S;Ψɍ;_7;[ڭఌ[ b cz 5oT$#m6p"}MkZHʂn>m]W+|DO7q5bX#bI惞1B؜9VpT{z2˳,0&7F/̫ku }_[lp<ђ4kPHZGԝ_˥E7`s|@̱[q"ok?]6u RrԠaXL`oE{h բRe,=#ټN @RI7$~EtOyId7_H i1g@,oCu6cx 6!l|DEq5,4G3%tVqGh/{({f؇303n {g4RĎa7ߟAJѐ%m_Nu$R44MBNH҃tV]$OV[Y"xnA?!Yl7ÿe҂~^/5)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)Actdb-2.5.1.dfsg/web/clamd.html0000644000175000017500000000424112245023514015751 0ustar mathieumathieu

Setting up ClamAV with CTDB

Prereqs

Configure CTDB as above and set it up to use public ipaddresses.
Verify that the CTDB cluster works.

Configuration

Configure clamd on each node on the cluster.

For details how to configure clamd check its documentation.

/etc/sysconfig/ctdb

Add the following lines to the /etc/sysconfig/ctdb configuration file.
  CTDB_MANAGES_CLAMD=yes
  CTDB_CLAMD_SOCKET="/path/to/clamd.sock"
Disable clamd in chkconfig so that it does not start by default. Instead CTDB will start/stop clamd as required.
  chkconfig clamd off

Events script

The CTDB distribution already comes with an events script for clamd in the file /etc/ctdb/events.d/31.clamd

There should not be any need to edit this file. What you need is to set it as executable, with command like this:
  chmod +x /etc/ctdb/events.d/31.clamd
To check if ctdb monitoring and handling with clamd, you can check outpout of command:
  ctdb scriptstatus

Restart your cluster

Next time your cluster restarts, CTDB will start managing the clamd service.

If the cluster is already in production you may not want to restart the entire cluster since this would disrupt services.
Insted you can just disable/enable the nodes one by one. Once a node becomes enabled again it will start the clamd service.

Follow the procedure below for each node, one node at a time :

1 Disable the node

Use the ctdb command to disable the node :
  ctdb -n NODE disable

2 Wait until the cluster has recovered

Use the ctdb tool to monitor until the cluster has recovered, i.e. Recovery mode is NORMAL. This should happen within seconds of when you disabled the node.
  ctdb status

3 Enable the node again

Re-enable the node again which will start the newly configured vsftp service.
  ctdb -n NODE enable

See also

The CLAMAV section in the ctdbd manpage.
  man ctdbd
ctdb-2.5.1.dfsg/web/documentation.html0000644000175000017500000000331112245023514017537 0ustar mathieumathieu

CTDB Documentation

The following documentation should get you started with CTDB. Man pages: Articles: ctdb-2.5.1.dfsg/tools/0000755000175000017500000000000012245023514014365 5ustar mathieumathieuctdb-2.5.1.dfsg/tools/ctdb_diagnostics0000755000175000017500000001761512245023514017630 0ustar mathieumathieu#!/bin/sh # a script to test the basic setup of a CTDB/Samba install # tridge@samba.org September 2007 # martin@meltin.net August 2010 usage () { cat >&2 < Comma separated list of nodes to operate on -c Ignore comment lines (starting with '#') in file comparisons -w Ignore whitespace in file comparisons --no-ads Do not use commands that assume an Active Directory Server EOF exit 1 } nodes=$(ctdb listnodes -Y | cut -d: -f2) bad_nodes="" diff_opts= no_ads=false parse_options () { temp=$(getopt -n "ctdb_diagnostics" -o "n:cwh" -l no-ads,help -- "$@") [ $? != 0 ] && usage eval set -- "$temp" while true ; do case "$1" in -n) nodes=$(echo "$2" | sed -e 's@,@ @g') ; shift 2 ;; -c) diff_opts="${diff_opts} -I ^#.*" ; shift ;; -w) diff_opts="${diff_opts} -w" ; shift ;; --no-ads) no_ads=true ; shift ;; --) shift ; break ;; -h|--help|*) usage ;; esac done [ $# -ne 0 ] && usage } parse_options "$@" # Use 5s ssh timeout if EXTRA_SSH_OPTS doesn't set a timeout. case "$EXTRA_SSH_OPTS" in *ConnectTimeout=*) : ;; *) export EXTRA_SSH_OPTS="${EXTRA_SSH_OPTS} -o ConnectTimeout=5" esac # Filter nodes. Remove any nodes we can't contact from $node and add # them to $bad_nodes. _nodes="" for _i in $nodes ; do if onnode $_i true >/dev/null 2>&1 ; then _nodes="${_nodes}${_nodes:+ }${_i}" else bad_nodes="${bad_nodes}${bad_nodes:+,}${_i}" fi done nodes="$_nodes" nodes_comma=$(echo $nodes | sed -e 's@[[:space:]]@,@g') PATH="$PATH:/sbin:/usr/sbin:/usr/lpp/mmfs/bin" # list of config files that must exist and that we check are the same # on the nodes if [ -d /etc/sysconfig ] ; then CONFIG_FILES_MUST="/etc/krb5.conf /etc/hosts /etc/ctdb/nodes /etc/sysconfig/ctdb /etc/resolv.conf /etc/nsswitch.conf /etc/sysctl.conf /etc/samba/smb.conf /etc/fstab /etc/multipath.conf /etc/pam.d/system-auth /etc/sysconfig/nfs /etc/exports /etc/vsftpd/vsftpd.conf" else CONFIG_FILES_MUST="/etc/krb5.conf /etc/hosts /etc/ctdb/nodes /etc/default/ctdb /etc/resolv.conf /etc/nsswitch.conf /etc/sysctl.conf /etc/samba/smb.conf /etc/fstab /etc/multipath.conf /etc/pam.d/system-auth /etc/default/nfs /etc/exports /etc/vsftpd/vsftpd.conf" fi # list of config files that may exist and should be checked that they # are the same on the nodes CONFIG_FILES_MAY="/etc/ctdb/public_addresses /etc/ctdb/static-routes" 2>&1 cat <> $ERRORS } show_file() { fname="$1" echo " ================================" echo " File: $fname" echo " `ls -l $fname 2>&1`" cat "$fname" 2>&1 | sed 's/^/ /' echo " ================================" } show_all() { echo "running $1 on nodes $nodes_comma" onnode $nodes_comma "hostname; date; $1 2>&1 | sed 's/^/ /'" 2>&1 } show_and_compare_files () { fmt="$1" ; shift for f ; do first=true for n in $nodes ; do if $first ; then onnode $n [ -r "$f" ] || { msg=$(printf "$fmt" "$f" $n) error "$msg" continue 2; } fstf=$tmpdir/`basename $f`.node$n onnode $n cat $f > $fstf 2>&1 echo " ================================" echo " File (on node $n): $f" echo " `onnode $n ls -l $f 2>&1`" cat "$fstf" | sed 's/^/ /' echo " ================================" first=false else echo "Testing for same config file $f on node $n" tmpf=$tmpdir/`basename $f`.node$n onnode $n cat $f > $tmpf 2>&1 diff $diff_opts $fstf $tmpf >/dev/null 2>&1 || { error "File $f is different on node $n" diff -u $diff_opts $fstf $tmpf } rm -f $tmpf fi done rm -f $fstf done } if ! tmpdir=$(mktemp -d) ; then echo "Unable to create a temporary directory" exit 1 fi ERRORS="${tmpdir}/diag_err" NUM_ERRORS=0 cat < /dev/null` show_all id "$WORKGROUP/Administrator" show_all "wbinfo -p" show_all "wbinfo --online-status" show_all "smbd -b" date echo "Diagnostics finished with $NUM_ERRORS errors" [ -r $ERRORS ] && { cat $ERRORS rm -f $ERRORS } rm -rf "$tmpdir" exit $NUM_ERRORS ctdb-2.5.1.dfsg/tools/ctdb_vacuum.c0000644000175000017500000001133312245023514017026 0ustar mathieumathieu/* ctdb control tool - database vacuum Copyright (C) Andrew Tridgell 2008 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #include "includes.h" #include "system/filesys.h" #include "system/network.h" #include "../include/ctdb_client.h" #include "../include/ctdb_private.h" #include "../common/rb_tree.h" #include "db_wrap.h" /* should be tunable */ #define TIMELIMIT() timeval_current_ofs(10, 0) struct vacuum_traverse_state { bool error; struct tdb_context *dest_db; }; /* traverse function for repacking */ static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private) { struct vacuum_traverse_state *state = (struct vacuum_traverse_state *)private; if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) { state->error = true; return -1; } return 0; } /* repack a tdb */ static int ctdb_repack_tdb(struct tdb_context *tdb) { struct tdb_context *tmp_db; struct vacuum_traverse_state state; if (tdb_transaction_start(tdb) != 0) { DEBUG(DEBUG_ERR,(__location__ " Failed to start transaction\n")); return -1; } tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL|TDB_DISALLOW_NESTING, O_RDWR|O_CREAT, 0); if (tmp_db == NULL) { DEBUG(DEBUG_ERR,(__location__ " Failed to create tmp_db\n")); tdb_transaction_cancel(tdb); return -1; } state.error = false; state.dest_db = tmp_db; if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) { DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying out\n")); tdb_transaction_cancel(tdb); tdb_close(tmp_db); return -1; } if (state.error) { DEBUG(DEBUG_ERR,(__location__ " Error during traversal\n")); tdb_transaction_cancel(tdb); tdb_close(tmp_db); return -1; } if (tdb_wipe_all(tdb) != 0) { DEBUG(DEBUG_ERR,(__location__ " Failed to wipe database\n")); tdb_transaction_cancel(tdb); tdb_close(tmp_db); return -1; } state.error = false; state.dest_db = tdb; if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) { DEBUG(DEBUG_ERR,(__location__ " Failed to traverse copying back\n")); tdb_transaction_cancel(tdb); tdb_close(tmp_db); return -1; } if (state.error) { DEBUG(DEBUG_ERR,(__location__ " Error during second traversal\n")); tdb_transaction_cancel(tdb); tdb_close(tmp_db); return -1; } tdb_close(tmp_db); if (tdb_transaction_commit(tdb) != 0) { DEBUG(DEBUG_ERR,(__location__ " Failed to commit\n")); return -1; } return 0; } /* repack one database */ static int ctdb_repack_db(struct ctdb_context *ctdb, uint32_t db_id, bool persistent, uint32_t repack_limit) { struct ctdb_db_context *ctdb_db; const char *name; int size; if (ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, db_id, ctdb, &name) != 0) { DEBUG(DEBUG_ERR,(__location__ " Failed to get name of db 0x%x\n", db_id)); return -1; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), name, persistent, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,(__location__ " Failed to attach to database '%s'\n", name)); return -1; } size = tdb_freelist_size(ctdb_db->ltdb->tdb); if (size == -1) { DEBUG(DEBUG_ERR,(__location__ " Failed to get freelist size for '%s'\n", name)); return -1; } if (size <= repack_limit) { return 0; } printf("Repacking %s with %u freelist entries\n", name, size); if (ctdb_repack_tdb(ctdb_db->ltdb->tdb) != 0) { DEBUG(DEBUG_ERR,(__location__ " Failed to repack '%s'\n", name)); return -1; } return 0; } /* repack all our databases */ int ctdb_repack(struct ctdb_context *ctdb, int argc, const char **argv) { struct ctdb_dbid_map *dbmap=NULL; int ret, i; /* a reasonable default limit to prevent us using too much memory */ uint32_t repack_limit = 10000; if (argc > 0) { repack_limit = atoi(argv[0]); } ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &dbmap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get dbids from local node\n")); return ret; } for (i=0;inum;i++) { if (ctdb_repack_db(ctdb, dbmap->dbs[i].dbid, dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT, repack_limit) != 0) { DEBUG(DEBUG_ERR,("Failed to repack db 0x%x\n", dbmap->dbs[i].dbid)); return -1; } } return 0; } ctdb-2.5.1.dfsg/tools/ltdbtool.c0000644000175000017500000002375112245023514016364 0ustar mathieumathieu/* * ctdb local tdb tool * * Copyright (C) Gregor Beck 2011 * Copyright (C) Michael Adam 2011 * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . */ #include #include #include #include #include /* isprint */ #include /* strstr */ #include /* mode_t */ #include /* S_IRUSR */ #include /* uint32_t */ #include /* struct sockaddr_in */ #include /* struct sockaddr */ #include /* MIN */ #include #include /* getopt */ #include #include "ctdb_protocol.h" enum { MAX_HEADER_SIZE=24, OUT_MODE = S_IRUSR | S_IWUSR, OUT_FLAGS = O_EXCL|O_CREAT|O_RDWR, }; union ltdb_header { struct ctdb_ltdb_header hdr; uint32_t uints[MAX_HEADER_SIZE/4]; }; static const union ltdb_header DEFAULT_HDR = { .hdr.dmaster = -1, }; static int help(const char* cmd) { fprintf(stdout, "" "Usage: %s [options] \n" "\n" "Options:\n" " -s {0|32|64} specify how to determine the ctdb record header size\n" " for the input database:\n" " 0: no ctdb header\n" " 32: ctdb header size of a 32 bit system (20 bytes)\n" " 64: ctdb header size of a 64 bit system (24 bytes)\n" " default: 32 or 64 depending on the system architecture\n" "\n" " -S the number of bytes to interpret as ctdb record header\n" " for the input database (beware!)\n" "\n" " -o {0|32|64} specify how to determine the ctdb record header size\n" " for the output database\n" " 0: no ctdb header\n" " 32: ctdb header size of a 32 bit system (20 bytes)\n" " 64: ctdb header size of a 64 bit system (24 bytes)\n" " default: 32 or 64 depending on the system architecture\n" "\n" " -O the number of bytes to interpret as ctdb record header\n" " for the output database (beware!)\n" "\n" " -e Include empty records, defaults to off\n" "\n" " -p print header (for the dump command), defaults to off\n" "\n" " -h print this help\n" "\n" "Commands:\n" " help print this help\n" " dump dump the db to stdout\n" " convert convert the db\n\n", cmd); return 0; } static int usage(const char* cmd) { fprintf(stderr, "Usage: %s dump [-e] [-p] [-s{0|32|64}] \n" " %s convert [-e] [-s{0|32|64}] [-o{0|32|64}] \n" " %s {help|-h}\n" , cmd, cmd, cmd); return -1; } static int ltdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT*, TDB_DATA, TDB_DATA, struct ctdb_ltdb_header*, void *), void *state, int hsize, bool skip_empty); struct write_record_ctx { TDB_CONTEXT* tdb; size_t hsize; int tdb_store_flags; }; static int write_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val, struct ctdb_ltdb_header* hdr, void* write_record_ctx); struct dump_record_ctx { FILE* file; void (*print_data)(FILE*, TDB_DATA); void (*dump_header)(struct dump_record_ctx*, struct ctdb_ltdb_header*); }; static int dump_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val, struct ctdb_ltdb_header* hdr, void* dump_record_ctx); static void print_data_tdbdump(FILE* file, TDB_DATA data); static void dump_header_full(struct dump_record_ctx*, struct ctdb_ltdb_header*); static void dump_header_nop(struct dump_record_ctx* c, struct ctdb_ltdb_header* h) {} static int dump_db(const char* iname, FILE* ofile, int hsize, bool dump_header, bool empty) { int ret = -1; TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0); if (!idb) { perror("tdbopen in"); } else { struct dump_record_ctx dump_ctx = { .file = ofile, .print_data = &print_data_tdbdump, .dump_header = dump_header ? &dump_header_full : &dump_header_nop, }; ret = ltdb_traverse(idb, &dump_record, &dump_ctx, hsize, !empty); tdb_close(idb); } return ret; } static int conv_db(const char* iname, const char* oname, size_t isize, size_t osize, bool keep_empty) { int ret = -1; TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0); if (!idb) { perror("tdbopen in"); } else { TDB_CONTEXT* odb = tdb_open(oname, 0, TDB_DEFAULT, OUT_FLAGS, OUT_MODE); if (!odb) { perror("tdbopen out"); } else { struct write_record_ctx ctx = { .tdb = odb, .hsize = osize, .tdb_store_flags = TDB_REPLACE, }; ret = ltdb_traverse(idb, &write_record, &ctx, isize, !keep_empty); tdb_close(odb); } tdb_close(idb); } return ret; } static bool parse_size(size_t* size, const char* arg, bool raw) { long val; errno = 0; val = strtol(arg, (char **) NULL, 10); if (errno != 0) { return false; } if (!raw) { switch(val) { case 0: break; case 32: val = 20; break; case 64: val = 24; break; default: return false; } } *size = MIN(val, MAX_HEADER_SIZE); return true; } int main(int argc, char* argv[]) { size_t isize = sizeof(struct ctdb_ltdb_header); size_t osize = sizeof(struct ctdb_ltdb_header); bool print_header = false; bool keep_empty = false; int opt; const char *cmd, *idb, *odb; while ((opt = getopt(argc, argv, "s:o:S:O:phe")) != -1) { switch (opt) { case 's': case 'S': if (!parse_size(&isize, optarg, isupper(opt))) { return usage(argv[0]); } break; case 'o': case 'O': if (!parse_size(&osize, optarg, isupper(opt))) { return usage(argv[0]); } break; case 'p': print_header = true; break; case 'e': keep_empty = true; break; case 'h': return help(argv[0]); default: return usage(argv[0]); } } if (argc - optind < 1) { return usage(argv[0]); } cmd = argv[optind]; if (strcmp(cmd, "help") == 0) { return help(argv[0]); } else if (strcmp(cmd, "dump") == 0) { int ret; if (argc - optind != 2) { return usage(argv[0]); } idb = argv[optind+1]; ret = dump_db(idb, stdout, isize, print_header, keep_empty); return (ret >= 0) ? 0 : ret; } else if (strcmp(cmd, "convert") == 0) { int ret; if (argc - optind != 3) { return usage(argv[0]); } idb = argv[optind+1]; odb = argv[optind+2]; ret = conv_db(idb, odb, isize, osize, keep_empty); return (ret >= 0) ? 0 : ret; } return usage(argv[0]); } struct ltdb_traverse_ctx { int (*fn)(TDB_CONTEXT*,TDB_DATA,TDB_DATA,struct ctdb_ltdb_header*,void *); void* state; size_t hsize; bool skip_empty; unsigned nempty; }; static int ltdb_traverse_fn(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val, void* ltdb_traverse_ctx) { struct ltdb_traverse_ctx* ctx = (struct ltdb_traverse_ctx*)ltdb_traverse_ctx; union ltdb_header hdr = DEFAULT_HDR; const size_t hsize = MIN(sizeof(hdr), ctx->hsize); if (val.dsize < hsize) { fprintf(stderr, "Value too short to contain a ctdb header: "); print_data_tdbdump(stderr, key); fprintf(stderr, " = "); print_data_tdbdump(stderr, val); fputc('\n', stderr); return -1; } if (val.dsize == hsize && ctx->skip_empty) { ctx->nempty++; return 0; } memcpy(&hdr, val.dptr, hsize); if (hdr.uints[5] != 0) { fprintf(stderr, "Warning: header padding isn't zero! Wrong header size?\n"); } val.dptr += ctx->hsize; val.dsize -= ctx->hsize; return ctx->fn(tdb, key, val, &hdr.hdr, ctx->state); } int ltdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *,TDB_DATA,TDB_DATA,struct ctdb_ltdb_header*,void *), void *state, int hsize, bool skip_empty) { struct ltdb_traverse_ctx ctx = { .fn = fn, .state = state, .hsize = hsize < 0 ? sizeof(struct ctdb_ltdb_header) : hsize, .skip_empty = skip_empty, .nempty = 0, }; int ret = tdb_traverse(tdb, <db_traverse_fn, &ctx); return (ret < 0) ? ret : (ret - ctx.nempty); } int write_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val, struct ctdb_ltdb_header* hdr, void* write_record_ctx) { struct write_record_ctx* ctx = (struct write_record_ctx*)write_record_ctx; if (ctx->hsize == 0) { if (tdb_store(ctx->tdb, key, val, ctx->tdb_store_flags) == -1) { fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb)); return -1; } } else { TDB_DATA h = { .dptr = (void*)hdr, .dsize = ctx->hsize, }; if(tdb_store(ctx->tdb, key, h, ctx->tdb_store_flags) == -1) { fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb)); return -1; } if(tdb_append(ctx->tdb, key, val) == -1) { fprintf(stderr, "tdb_append: %s\n", tdb_errorstr(ctx->tdb)); return -1; } } return 0; } int dump_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val, struct ctdb_ltdb_header* hdr, void* dump_record_ctx) { struct dump_record_ctx* ctx = (struct dump_record_ctx*)dump_record_ctx; fprintf(ctx->file, "{\nkey(%d) = ", (int)key.dsize); ctx->print_data(ctx->file, key); fputc('\n', ctx->file); ctx->dump_header(ctx, hdr); fprintf(ctx->file, "data(%d) = ", (int)val.dsize); ctx->print_data(ctx->file, val); fprintf(ctx->file, "\n}\n"); return 0; } void dump_header_full(struct dump_record_ctx* c, struct ctdb_ltdb_header* h) { fprintf(c->file, "dmaster: %d\nrsn: %llu\nflags: 0x%X\n", (int)h->dmaster, (unsigned long long)h->rsn, h->flags); } void print_data_tdbdump(FILE* file, TDB_DATA data) { unsigned char *ptr = data.dptr; fputc('"', file); while (data.dsize--) { if (isprint(*ptr) && !strchr("\"\\", *ptr)) { fputc(*ptr, file); } else { fprintf(file, "\\%02X", *ptr); } ptr++; } fputc('"',file); } ctdb-2.5.1.dfsg/tools/ctdb.c0000644000175000017500000050273212245023514015456 0ustar mathieumathieu/* ctdb control tool Copyright (C) Andrew Tridgell 2007 Copyright (C) Ronnie Sahlberg 2007 This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, see . */ #include "includes.h" #include "system/time.h" #include "system/filesys.h" #include "system/network.h" #include "system/locale.h" #include "popt.h" #include "cmdline.h" #include "../include/ctdb_version.h" #include "../include/ctdb_client.h" #include "../include/ctdb_private.h" #include "../common/rb_tree.h" #include "db_wrap.h" #define ERR_TIMEOUT 20 /* timed out trying to reach node */ #define ERR_NONODE 21 /* node does not exist */ #define ERR_DISNODE 22 /* node is disconnected */ static void usage(void); static struct { int timelimit; uint32_t pnn; uint32_t *nodes; int machinereadable; int verbose; int maxruntime; int printemptyrecords; int printdatasize; int printlmaster; int printhash; int printrecordflags; } options; #define LONGTIMEOUT options.timelimit*10 #define TIMELIMIT() timeval_current_ofs(options.timelimit, 0) #define LONGTIMELIMIT() timeval_current_ofs(LONGTIMEOUT, 0) static int control_version(struct ctdb_context *ctdb, int argc, const char **argv) { printf("CTDB version: %s\n", CTDB_VERSION_STRING); return 0; } #define CTDB_NOMEM_ABORT(p) do { if (!(p)) { \ DEBUG(DEBUG_ALERT,("ctdb fatal error: %s\n", \ "Out of memory in " __location__ )); \ abort(); \ }} while (0) static uint32_t getpnn(struct ctdb_context *ctdb) { if ((options.pnn == CTDB_BROADCAST_ALL) || (options.pnn == CTDB_MULTICAST)) { DEBUG(DEBUG_ERR, ("Cannot get PNN for node %u\n", options.pnn)); exit(1); } if (options.pnn == CTDB_CURRENT_NODE) { return ctdb_get_pnn(ctdb); } else { return options.pnn; } } static void assert_single_node_only(void) { if ((options.pnn == CTDB_BROADCAST_ALL) || (options.pnn == CTDB_MULTICAST)) { DEBUG(DEBUG_ERR, ("This control can not be applied to multiple PNNs\n")); exit(1); } } /* Pretty print the flags to a static buffer in human-readable format. * This never returns NULL! */ static const char *pretty_print_flags(uint32_t flags) { int j; static const struct { uint32_t flag; const char *name; } flag_names[] = { { NODE_FLAGS_DISCONNECTED, "DISCONNECTED" }, { NODE_FLAGS_PERMANENTLY_DISABLED, "DISABLED" }, { NODE_FLAGS_BANNED, "BANNED" }, { NODE_FLAGS_UNHEALTHY, "UNHEALTHY" }, { NODE_FLAGS_DELETED, "DELETED" }, { NODE_FLAGS_STOPPED, "STOPPED" }, { NODE_FLAGS_INACTIVE, "INACTIVE" }, }; static char flags_str[512]; /* Big enough to contain all flag names */ flags_str[0] = '\0'; for (j=0;j= 'a' && h <= 'f') return h - 'a' + 10; if (h >= 'A' && h <= 'F') return h - 'f' + 10; return h - '0'; } static TDB_DATA hextodata(TALLOC_CTX *mem_ctx, const char *str) { int i, len; TDB_DATA key = {NULL, 0}; len = strlen(str); if (len & 0x01) { DEBUG(DEBUG_ERR,("Key specified with odd number of hexadecimal digits\n")); return key; } key.dsize = len>>1; key.dptr = talloc_size(mem_ctx, key.dsize); for (i=0; i < len/2; i++) { key.dptr[i] = h2i(str[i*2]) << 4 | h2i(str[i*2+1]); } return key; } /* Parse a nodestring. Parameter dd_ok controls what happens to nodes * that are disconnected or deleted. If dd_ok is true those nodes are * included in the output list of nodes. If dd_ok is false, those * nodes are filtered from the "all" case and cause an error if * explicitly specified. */ static bool parse_nodestring(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, const char * nodestring, uint32_t current_pnn, bool dd_ok, uint32_t **nodes, uint32_t *pnn_mode) { TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); int n; uint32_t i; struct ctdb_node_map *nodemap; int ret; *nodes = NULL; ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n")); talloc_free(tmp_ctx); exit(10); } if (nodestring != NULL) { *nodes = talloc_array(mem_ctx, uint32_t, 0); if (*nodes == NULL) { goto failed; } n = 0; if (strcmp(nodestring, "all") == 0) { *pnn_mode = CTDB_BROADCAST_ALL; /* all */ for (i = 0; i < nodemap->num; i++) { if ((nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED | NODE_FLAGS_DELETED)) && !dd_ok) { continue; } *nodes = talloc_realloc(mem_ctx, *nodes, uint32_t, n+1); if (*nodes == NULL) { goto failed; } (*nodes)[n] = i; n++; } } else { /* x{,y...} */ char *ns, *tok; ns = talloc_strdup(tmp_ctx, nodestring); tok = strtok(ns, ","); while (tok != NULL) { uint32_t pnn; char *endptr; i = (uint32_t)strtoul(tok, &endptr, 0); if (i == 0 && tok == endptr) { DEBUG(DEBUG_ERR, ("Invalid node %s\n", tok)); talloc_free(tmp_ctx); exit(ERR_NONODE); } if (i >= nodemap->num) { DEBUG(DEBUG_ERR, ("Node %u does not exist\n", i)); talloc_free(tmp_ctx); exit(ERR_NONODE); } if ((nodemap->nodes[i].flags & (NODE_FLAGS_DISCONNECTED | NODE_FLAGS_DELETED)) && !dd_ok) { DEBUG(DEBUG_ERR, ("Node %u has status %s\n", i, pretty_print_flags(nodemap->nodes[i].flags))); talloc_free(tmp_ctx); exit(ERR_DISNODE); } if ((pnn = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), i)) < 0) { DEBUG(DEBUG_ERR, ("Can not access node %u. Node is not operational.\n", i)); talloc_free(tmp_ctx); exit(10); } *nodes = talloc_realloc(mem_ctx, *nodes, uint32_t, n+1); if (*nodes == NULL) { goto failed; } (*nodes)[n] = i; n++; tok = strtok(NULL, ","); } talloc_free(ns); if (n == 1) { *pnn_mode = (*nodes)[0]; } else { *pnn_mode = CTDB_MULTICAST; } } } else { /* default - no nodes specified */ *nodes = talloc_array(mem_ctx, uint32_t, 1); if (*nodes == NULL) { goto failed; } *pnn_mode = CTDB_CURRENT_NODE; if (((*nodes)[0] = ctdb_ctrl_getpnn(ctdb, TIMELIMIT(), current_pnn)) < 0) { goto failed; } } talloc_free(tmp_ctx); return true; failed: talloc_free(tmp_ctx); return false; } /* check if a database exists */ static bool db_exists(struct ctdb_context *ctdb, const char *dbarg, uint32_t *dbid, const char **dbname, uint8_t *flags) { int i, ret; struct ctdb_dbid_map *dbmap=NULL; bool dbid_given = false, found = false; uint32_t id; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); const char *name; ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &dbmap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn)); goto fail; } if (strncmp(dbarg, "0x", 2) == 0) { id = strtoul(dbarg, NULL, 0); dbid_given = true; } for(i=0; inum; i++) { if (dbid_given) { if (id == dbmap->dbs[i].dbid) { found = true; break; } } else { ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].dbid)); goto fail; } if (strcmp(name, dbarg) == 0) { id = dbmap->dbs[i].dbid; found = true; break; } } } if (found && dbid_given && dbname != NULL) { ret = ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get dbname from dbid %u\n", dbmap->dbs[i].dbid)); found = false; goto fail; } } if (found) { if (dbid) *dbid = id; if (dbname) *dbname = talloc_strdup(ctdb, name); if (flags) *flags = dbmap->dbs[i].flags; } else { DEBUG(DEBUG_ERR,("No database matching '%s' found\n", dbarg)); } fail: talloc_free(tmp_ctx); return found; } /* see if a process exists */ static int control_process_exists(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t pnn, pid; int ret; if (argc < 1) { usage(); } if (sscanf(argv[0], "%u:%u", &pnn, &pid) != 2) { DEBUG(DEBUG_ERR, ("Badly formed pnn:pid\n")); return -1; } ret = ctdb_ctrl_process_exists(ctdb, pnn, pid); if (ret == 0) { printf("%u:%u exists\n", pnn, pid); } else { printf("%u:%u does not exist\n", pnn, pid); } return ret; } /* display statistics structure */ static void show_statistics(struct ctdb_statistics *s, int show_header) { TALLOC_CTX *tmp_ctx = talloc_new(NULL); int i; const char *prefix=NULL; int preflen=0; int tmp, days, hours, minutes, seconds; const struct { const char *name; uint32_t offset; } fields[] = { #define STATISTICS_FIELD(n) { #n, offsetof(struct ctdb_statistics, n) } STATISTICS_FIELD(num_clients), STATISTICS_FIELD(frozen), STATISTICS_FIELD(recovering), STATISTICS_FIELD(num_recoveries), STATISTICS_FIELD(client_packets_sent), STATISTICS_FIELD(client_packets_recv), STATISTICS_FIELD(node_packets_sent), STATISTICS_FIELD(node_packets_recv), STATISTICS_FIELD(keepalive_packets_sent), STATISTICS_FIELD(keepalive_packets_recv), STATISTICS_FIELD(node.req_call), STATISTICS_FIELD(node.reply_call), STATISTICS_FIELD(node.req_dmaster), STATISTICS_FIELD(node.reply_dmaster), STATISTICS_FIELD(node.reply_error), STATISTICS_FIELD(node.req_message), STATISTICS_FIELD(node.req_control), STATISTICS_FIELD(node.reply_control), STATISTICS_FIELD(client.req_call), STATISTICS_FIELD(client.req_message), STATISTICS_FIELD(client.req_control), STATISTICS_FIELD(timeouts.call), STATISTICS_FIELD(timeouts.control), STATISTICS_FIELD(timeouts.traverse), STATISTICS_FIELD(locks.num_calls), STATISTICS_FIELD(locks.num_current), STATISTICS_FIELD(locks.num_pending), STATISTICS_FIELD(locks.num_failed), STATISTICS_FIELD(total_calls), STATISTICS_FIELD(pending_calls), STATISTICS_FIELD(childwrite_calls), STATISTICS_FIELD(pending_childwrite_calls), STATISTICS_FIELD(memory_used), STATISTICS_FIELD(max_hop_count), STATISTICS_FIELD(total_ro_delegations), STATISTICS_FIELD(total_ro_revokes), }; tmp = s->statistics_current_time.tv_sec - s->statistics_start_time.tv_sec; seconds = tmp%60; tmp /= 60; minutes = tmp%60; tmp /= 60; hours = tmp%24; tmp /= 24; days = tmp; if (options.machinereadable){ if (show_header) { printf("CTDB version:"); printf("Current time of statistics:"); printf("Statistics collected since:"); for (i=0;istatistics_current_time.tv_sec); printf("%d:", (int)s->statistics_start_time.tv_sec); for (i=0;ireclock.ctdbd.num); printf("%.6f:", s->reclock.ctdbd.min); printf("%.6f:", s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0); printf("%.6f:", s->reclock.ctdbd.max); printf("%d:", s->reclock.recd.num); printf("%.6f:", s->reclock.recd.min); printf("%.6f:", s->reclock.recd.num?s->reclock.recd.total/s->reclock.recd.num:0.0); printf("%.6f:", s->reclock.recd.max); printf("%d:", s->call_latency.num); printf("%.6f:", s->call_latency.min); printf("%.6f:", s->call_latency.num?s->call_latency.total/s->call_latency.num:0.0); printf("%.6f:", s->call_latency.max); printf("%d:", s->childwrite_latency.num); printf("%.6f:", s->childwrite_latency.min); printf("%.6f:", s->childwrite_latency.num?s->childwrite_latency.total/s->childwrite_latency.num:0.0); printf("%.6f:", s->childwrite_latency.max); printf("\n"); } else { printf("CTDB version %u\n", CTDB_VERSION); printf("Current time of statistics : %s", ctime(&s->statistics_current_time.tv_sec)); printf("Statistics collected since : (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&s->statistics_start_time.tv_sec)); for (i=0;ihop_count_bucket[i]); } printf("\n"); printf(" lock_buckets:"); for (i=0; ilocks.buckets[i]); } printf("\n"); printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "locks_latency MIN/AVG/MAX", s->locks.latency.min, s->locks.latency.num?s->locks.latency.total/s->locks.latency.num:0.0, s->locks.latency.max, s->locks.latency.num); printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "reclock_ctdbd MIN/AVG/MAX", s->reclock.ctdbd.min, s->reclock.ctdbd.num?s->reclock.ctdbd.total/s->reclock.ctdbd.num:0.0, s->reclock.ctdbd.max, s->reclock.ctdbd.num); printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "reclock_recd MIN/AVG/MAX", s->reclock.recd.min, s->reclock.recd.num?s->reclock.recd.total/s->reclock.recd.num:0.0, s->reclock.recd.max, s->reclock.recd.num); printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "call_latency MIN/AVG/MAX", s->call_latency.min, s->call_latency.num?s->call_latency.total/s->call_latency.num:0.0, s->call_latency.max, s->call_latency.num); printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "childwrite_latency MIN/AVG/MAX", s->childwrite_latency.min, s->childwrite_latency.num?s->childwrite_latency.total/s->childwrite_latency.num:0.0, s->childwrite_latency.max, s->childwrite_latency.num); } talloc_free(tmp_ctx); } /* display remote ctdb statistics combined from all nodes */ static int control_statistics_all(struct ctdb_context *ctdb) { int ret, i; struct ctdb_statistics statistics; uint32_t *nodes; uint32_t num_nodes; nodes = ctdb_get_connected_nodes(ctdb, TIMELIMIT(), ctdb, &num_nodes); CTDB_NO_MEMORY(ctdb, nodes); ZERO_STRUCT(statistics); for (i=0;inum;i++) { if (stats->stats[i].statistics_start_time.tv_sec == 0) { continue; } show_statistics(&stats->stats[i], i==0); if (i == num_records) { break; } } return 0; } /* display remote ctdb db statistics */ static int control_dbstatistics(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_db_statistics *dbstat; int i; uint32_t db_id; int num_hot_keys; int ret; if (argc < 1) { usage(); } if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) { return -1; } ret = ctdb_ctrl_dbstatistics(ctdb, options.pnn, db_id, tmp_ctx, &dbstat); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to read db statistics from node\n")); talloc_free(tmp_ctx); return -1; } printf("DB Statistics: %s\n", argv[0]); printf(" %*s%-22s%*s%10u\n", 0, "", "ro_delegations", 4, "", dbstat->db_ro_delegations); printf(" %*s%-22s%*s%10u\n", 0, "", "ro_revokes", 4, "", dbstat->db_ro_delegations); printf(" %s\n", "locks"); printf(" %*s%-22s%*s%10u\n", 4, "", "total", 0, "", dbstat->locks.num_calls); printf(" %*s%-22s%*s%10u\n", 4, "", "failed", 0, "", dbstat->locks.num_failed); printf(" %*s%-22s%*s%10u\n", 4, "", "current", 0, "", dbstat->locks.num_current); printf(" %*s%-22s%*s%10u\n", 4, "", "pending", 0, "", dbstat->locks.num_pending); printf(" %s", "hop_count_buckets:"); for (i=0; ihop_count_bucket[i]); } printf("\n"); printf(" %s", "lock_buckets:"); for (i=0; ilocks.buckets[i]); } printf("\n"); printf(" %-30s %.6f/%.6f/%.6f sec out of %d\n", "locks_latency MIN/AVG/MAX", dbstat->locks.latency.min, (dbstat->locks.latency.num ? dbstat->locks.latency.total /dbstat->locks.latency.num : 0.0), dbstat->locks.latency.max, dbstat->locks.latency.num); num_hot_keys = 0; for (i=0; inum_hot_keys; i++) { if (dbstat->hot_keys[i].count > 0) { num_hot_keys++; } } dbstat->num_hot_keys = num_hot_keys; printf(" Num Hot Keys: %d\n", dbstat->num_hot_keys); for (i = 0; i < dbstat->num_hot_keys; i++) { int j; printf(" Count:%d Key:", dbstat->hot_keys[i].count); for (j = 0; j < dbstat->hot_keys[i].key.dsize; j++) { printf("%02x", dbstat->hot_keys[i].key.dptr[j]&0xff); } printf("\n"); } talloc_free(tmp_ctx); return 0; } /* display uptime of remote node */ static int control_uptime(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; struct ctdb_uptime *uptime = NULL; int tmp, days, hours, minutes, seconds; ret = ctdb_ctrl_uptime(ctdb, ctdb, TIMELIMIT(), options.pnn, &uptime); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get uptime from node %u\n", options.pnn)); return ret; } if (options.machinereadable){ printf(":Current Node Time:Ctdb Start Time:Last Recovery/Failover Time:Last Recovery/IPFailover Duration:\n"); printf(":%u:%u:%u:%lf\n", (unsigned int)uptime->current_time.tv_sec, (unsigned int)uptime->ctdbd_start_time.tv_sec, (unsigned int)uptime->last_recovery_finished.tv_sec, timeval_delta(&uptime->last_recovery_finished, &uptime->last_recovery_started) ); return 0; } printf("Current time of node : %s", ctime(&uptime->current_time.tv_sec)); tmp = uptime->current_time.tv_sec - uptime->ctdbd_start_time.tv_sec; seconds = tmp%60; tmp /= 60; minutes = tmp%60; tmp /= 60; hours = tmp%24; tmp /= 24; days = tmp; printf("Ctdbd start time : (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&uptime->ctdbd_start_time.tv_sec)); tmp = uptime->current_time.tv_sec - uptime->last_recovery_finished.tv_sec; seconds = tmp%60; tmp /= 60; minutes = tmp%60; tmp /= 60; hours = tmp%24; tmp /= 24; days = tmp; printf("Time of last recovery/failover: (%03d %02d:%02d:%02d) %s", days, hours, minutes, seconds, ctime(&uptime->last_recovery_finished.tv_sec)); printf("Duration of last recovery/failover: %lf seconds\n", timeval_delta(&uptime->last_recovery_finished, &uptime->last_recovery_started)); return 0; } /* show the PNN of the current node */ static int control_pnn(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t mypnn; mypnn = getpnn(ctdb); printf("PNN:%d\n", mypnn); return 0; } struct pnn_node { struct pnn_node *next; const char *addr; int pnn; }; static struct pnn_node *read_nodes_file(TALLOC_CTX *mem_ctx) { const char *nodes_list; int nlines; char **lines; int i, pnn; struct pnn_node *pnn_nodes = NULL; struct pnn_node *pnn_node; struct pnn_node *tmp_node; /* read the nodes file */ nodes_list = getenv("CTDB_NODES"); if (nodes_list == NULL) { nodes_list = talloc_asprintf(mem_ctx, "%s/nodes", getenv("CTDB_BASE")); if (nodes_list == NULL) { DEBUG(DEBUG_ALERT,(__location__ " Out of memory\n")); exit(1); } } lines = file_lines_load(nodes_list, &nlines, mem_ctx); if (lines == NULL) { return NULL; } while (nlines > 0 && strcmp(lines[nlines-1], "") == 0) { nlines--; } for (i=0, pnn=0; ipnn = pnn++; pnn_node->addr = talloc_strdup(pnn_node, node); pnn_node->next = pnn_nodes; pnn_nodes = pnn_node; } /* swap them around so we return them in incrementing order */ pnn_node = pnn_nodes; pnn_nodes = NULL; while (pnn_node) { tmp_node = pnn_node; pnn_node = pnn_node->next; tmp_node->next = pnn_nodes; pnn_nodes = tmp_node; } return pnn_nodes; } /* show the PNN of the current node discover the pnn by loading the nodes file and try to bind to all addresses one at a time until the ip address is found. */ static int control_xpnn(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *mem_ctx = talloc_new(NULL); struct pnn_node *pnn_nodes; struct pnn_node *pnn_node; assert_single_node_only(); pnn_nodes = read_nodes_file(mem_ctx); if (pnn_nodes == NULL) { DEBUG(DEBUG_ERR,("Failed to read nodes file\n")); talloc_free(mem_ctx); return -1; } for(pnn_node=pnn_nodes;pnn_node;pnn_node=pnn_node->next) { ctdb_sock_addr addr; if (parse_ip(pnn_node->addr, NULL, 63999, &addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s' in nodes file\n", pnn_node->addr)); talloc_free(mem_ctx); return -1; } if (ctdb_sys_have_ip(&addr)) { printf("PNN:%d\n", pnn_node->pnn); talloc_free(mem_ctx); return 0; } } printf("Failed to detect which PNN this node is\n"); talloc_free(mem_ctx); return -1; } /* Helpers for ctdb status */ static bool is_partially_online(struct ctdb_context *ctdb, struct ctdb_node_and_flags *node) { TALLOC_CTX *tmp_ctx = talloc_new(NULL); int j; bool ret = false; if (node->flags == 0) { struct ctdb_control_get_ifaces *ifaces; if (ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(), node->pnn, tmp_ctx, &ifaces) == 0) { for (j=0; j < ifaces->num; j++) { if (ifaces->ifaces[j].link_state != 0) { continue; } ret = true; break; } } } talloc_free(tmp_ctx); return ret; } static void control_status_header_machine(void) { printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped" ":Inactive:PartiallyOnline:ThisNode:\n"); } static int control_status_1_machine(struct ctdb_context *ctdb, int mypnn, struct ctdb_node_and_flags *node) { printf(":%d:%s:%d:%d:%d:%d:%d:%d:%d:%c:\n", node->pnn, ctdb_addr_to_str(&node->addr), !!(node->flags&NODE_FLAGS_DISCONNECTED), !!(node->flags&NODE_FLAGS_BANNED), !!(node->flags&NODE_FLAGS_PERMANENTLY_DISABLED), !!(node->flags&NODE_FLAGS_UNHEALTHY), !!(node->flags&NODE_FLAGS_STOPPED), !!(node->flags&NODE_FLAGS_INACTIVE), is_partially_online(ctdb, node) ? 1 : 0, (node->pnn == mypnn)?'Y':'N'); return node->flags; } static int control_status_1_human(struct ctdb_context *ctdb, int mypnn, struct ctdb_node_and_flags *node) { printf("pnn:%d %-16s %s%s\n", node->pnn, ctdb_addr_to_str(&node->addr), is_partially_online(ctdb, node) ? "PARTIALLYONLINE" : pretty_print_flags(node->flags), node->pnn == mypnn?" (THIS NODE)":""); return node->flags; } /* display remote ctdb status */ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); int i; struct ctdb_vnn_map *vnnmap=NULL; struct ctdb_node_map *nodemap=NULL; uint32_t recmode, recmaster, mypnn; int num_deleted_nodes = 0; int ret; mypnn = getpnn(ctdb); ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } if (options.machinereadable) { control_status_header_machine(); for (i=0;inum;i++) { if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) { continue; } (void) control_status_1_machine(ctdb, mypnn, &nodemap->nodes[i]); } talloc_free(tmp_ctx); return 0; } for (i=0; inum; i++) { if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) { num_deleted_nodes++; } } if (num_deleted_nodes == 0) { printf("Number of nodes:%d\n", nodemap->num); } else { printf("Number of nodes:%d (including %d deleted nodes)\n", nodemap->num, num_deleted_nodes); } for(i=0;inum;i++){ if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) { continue; } (void) control_status_1_human(ctdb, mypnn, &nodemap->nodes[i]); } ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &vnnmap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } if (vnnmap->generation == INVALID_GENERATION) { printf("Generation:INVALID\n"); } else { printf("Generation:%d\n",vnnmap->generation); } printf("Size:%d\n",vnnmap->size); for(i=0;isize;i++){ printf("hash:%d lmaster:%d\n", i, vnnmap->map[i]); } ret = ctdb_ctrl_getrecmode(ctdb, tmp_ctx, TIMELIMIT(), options.pnn, &recmode); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get recmode from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } printf("Recovery mode:%s (%d)\n",recmode==CTDB_RECOVERY_NORMAL?"NORMAL":"RECOVERY",recmode); ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, TIMELIMIT(), options.pnn, &recmaster); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } printf("Recovery master:%d\n",recmaster); talloc_free(tmp_ctx); return 0; } static int control_nodestatus(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); int i, ret; struct ctdb_node_map *nodemap=NULL; uint32_t * nodes; uint32_t pnn_mode, mypnn; if (argc > 1) { usage(); } if (!parse_nodestring(ctdb, tmp_ctx, argc == 1 ? argv[0] : NULL, options.pnn, true, &nodes, &pnn_mode)) { return -1; } if (options.machinereadable) { control_status_header_machine(); } else if (pnn_mode == CTDB_BROADCAST_ALL) { printf("Number of nodes:%d\n", (int) talloc_array_length(nodes)); } mypnn = getpnn(ctdb); ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } ret = 0; for (i = 0; i < talloc_array_length(nodes); i++) { if (options.machinereadable) { ret |= control_status_1_machine(ctdb, mypnn, &nodemap->nodes[nodes[i]]); } else { ret |= control_status_1_human(ctdb, mypnn, &nodemap->nodes[nodes[i]]); } } talloc_free(tmp_ctx); return ret; } struct natgw_node { struct natgw_node *next; const char *addr; }; static int find_natgw(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap, uint32_t flags, uint32_t *pnn, const char **ip) { int i; uint32_t capabilities; int ret; for (i=0;inum;i++) { if (!(nodemap->nodes[i].flags & flags)) { ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, &capabilities); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", nodemap->nodes[i].pnn)); return -1; } if (!(capabilities&CTDB_CAP_NATGW)) { continue; } *pnn = nodemap->nodes[i].pnn; *ip = ctdb_addr_to_str(&nodemap->nodes[i].addr); return 0; } } return 2; /* matches ENOENT */ } /* display the list of nodes belonging to this natgw configuration */ static int control_natgwlist(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); int i, ret; const char *natgw_list; int nlines; char **lines; struct natgw_node *natgw_nodes = NULL; struct natgw_node *natgw_node; struct ctdb_node_map *nodemap=NULL; uint32_t mypnn, pnn; const char *ip; /* When we have some nodes that could be the NATGW, make a * series of attempts to find the first node that doesn't have * certain status flags set. */ uint32_t exclude_flags[] = { /* Look for a nice healthy node */ NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED|NODE_FLAGS_BANNED|NODE_FLAGS_UNHEALTHY, /* If not found, an UNHEALTHY/BANNED node will do */ NODE_FLAGS_DISCONNECTED|NODE_FLAGS_STOPPED|NODE_FLAGS_DELETED, /* If not found, a STOPPED node will do */ NODE_FLAGS_DISCONNECTED|NODE_FLAGS_DELETED, 0, }; /* read the natgw nodes file into a linked list */ natgw_list = getenv("CTDB_NATGW_NODES"); if (natgw_list == NULL) { natgw_list = talloc_asprintf(tmp_ctx, "%s/natgw_nodes", getenv("CTDB_BASE")); if (natgw_list == NULL) { DEBUG(DEBUG_ALERT,(__location__ " Out of memory\n")); exit(1); } } lines = file_lines_load(natgw_list, &nlines, ctdb); if (lines == NULL) { ctdb_set_error(ctdb, "Failed to load natgw node list '%s'\n", natgw_list); talloc_free(tmp_ctx); return -1; } for (i=0;iaddr = talloc_strdup(natgw_node, node); CTDB_NO_MEMORY(ctdb, natgw_node->addr); natgw_node->next = natgw_nodes; natgw_nodes = natgw_node; } ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node.\n")); talloc_free(tmp_ctx); return -1; } /* Trim the nodemap so it only includes connected nodes in the * current natgw group. */ i=0; while(inum) { for(natgw_node=natgw_nodes;natgw_node;natgw_node=natgw_node->next) { if (!strcmp(natgw_node->addr, ctdb_addr_to_str(&nodemap->nodes[i].addr))) { break; } } /* this node was not in the natgw so we just remove it from * the list */ if ((natgw_node == NULL) || (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) ) { int j; for (j=i+1; jnum; j++) { nodemap->nodes[j-1] = nodemap->nodes[j]; } nodemap->num--; continue; } i++; } ret = 2; /* matches ENOENT */ pnn = -1; ip = "0.0.0.0"; for (i = 0; exclude_flags[i] != 0; i++) { ret = find_natgw(ctdb, nodemap, exclude_flags[i], &pnn, &ip); if (ret == -1) { goto done; } if (ret == 0) { break; } } if (options.machinereadable) { printf(":Node:IP:\n"); printf(":%d:%s:\n", pnn, ip); } else { printf("%d %s\n", pnn, ip); } /* print the pruned list of nodes belonging to this natgw list */ mypnn = getpnn(ctdb); if (options.machinereadable) { control_status_header_machine(); } else { printf("Number of nodes:%d\n", nodemap->num); } for(i=0;inum;i++){ if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) { continue; } if (options.machinereadable) { control_status_1_machine(ctdb, mypnn, &(nodemap->nodes[i])); } else { control_status_1_human(ctdb, mypnn, &(nodemap->nodes[i])); } } done: talloc_free(tmp_ctx); return ret; } /* display the status of the scripts for monitoring (or other events) */ static int control_one_scriptstatus(struct ctdb_context *ctdb, enum ctdb_eventscript_call type) { struct ctdb_scripts_wire *script_status; int ret, i; ret = ctdb_ctrl_getscriptstatus(ctdb, TIMELIMIT(), options.pnn, ctdb, type, &script_status); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get script status from node %u\n", options.pnn)); return ret; } if (script_status == NULL) { if (!options.machinereadable) { printf("%s cycle never run\n", ctdb_eventscript_call_names[type]); } return 0; } if (!options.machinereadable) { printf("%d scripts were executed last %s cycle\n", script_status->num_scripts, ctdb_eventscript_call_names[type]); } for (i=0; inum_scripts; i++) { const char *status = NULL; switch (script_status->scripts[i].status) { case -ETIME: status = "TIMEDOUT"; break; case -ENOEXEC: status = "DISABLED"; break; case 0: status = "OK"; break; default: if (script_status->scripts[i].status > 0) status = "ERROR"; break; } if (options.machinereadable) { printf(":%s:%s:%i:%s:%lu.%06lu:%lu.%06lu:%s:\n", ctdb_eventscript_call_names[type], script_status->scripts[i].name, script_status->scripts[i].status, status, (long)script_status->scripts[i].start.tv_sec, (long)script_status->scripts[i].start.tv_usec, (long)script_status->scripts[i].finished.tv_sec, (long)script_status->scripts[i].finished.tv_usec, script_status->scripts[i].output); continue; } if (status) printf("%-20s Status:%s ", script_status->scripts[i].name, status); else /* Some other error, eg from stat. */ printf("%-20s Status:CANNOT RUN (%s)", script_status->scripts[i].name, strerror(-script_status->scripts[i].status)); if (script_status->scripts[i].status >= 0) { printf("Duration:%.3lf ", timeval_delta(&script_status->scripts[i].finished, &script_status->scripts[i].start)); } if (script_status->scripts[i].status != -ENOEXEC) { printf("%s", ctime(&script_status->scripts[i].start.tv_sec)); if (script_status->scripts[i].status != 0) { printf(" OUTPUT:%s\n", script_status->scripts[i].output); } } else { printf("\n"); } } return 0; } static int control_scriptstatus(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; enum ctdb_eventscript_call type, min, max; const char *arg; if (argc > 1) { DEBUG(DEBUG_ERR, ("Unknown arguments to scriptstatus\n")); return -1; } if (argc == 0) arg = ctdb_eventscript_call_names[CTDB_EVENT_MONITOR]; else arg = argv[0]; for (type = 0; type < CTDB_EVENT_MAX; type++) { if (strcmp(arg, ctdb_eventscript_call_names[type]) == 0) { min = type; max = type+1; break; } } if (type == CTDB_EVENT_MAX) { if (strcmp(arg, "all") == 0) { min = 0; max = CTDB_EVENT_MAX; } else { DEBUG(DEBUG_ERR, ("Unknown event type %s\n", argv[0])); return -1; } } if (options.machinereadable) { printf(":Type:Name:Code:Status:Start:End:Error Output...:\n"); } for (type = min; type < max; type++) { ret = control_one_scriptstatus(ctdb, type); if (ret != 0) { return ret; } } return 0; } /* enable an eventscript */ static int control_enablescript(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; if (argc < 1) { usage(); } ret = ctdb_ctrl_enablescript(ctdb, TIMELIMIT(), options.pnn, argv[0]); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to enable script %s on node %u\n", argv[0], options.pnn)); return ret; } return 0; } /* disable an eventscript */ static int control_disablescript(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; if (argc < 1) { usage(); } ret = ctdb_ctrl_disablescript(ctdb, TIMELIMIT(), options.pnn, argv[0]); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to disable script %s on node %u\n", argv[0], options.pnn)); return ret; } return 0; } /* display the pnn of the recovery master */ static int control_recmaster(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t recmaster; int ret; ret = ctdb_ctrl_getrecmaster(ctdb, ctdb, TIMELIMIT(), options.pnn, &recmaster); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn)); return -1; } printf("%d\n",recmaster); return 0; } /* add a tickle to a public address */ static int control_add_tickle(struct ctdb_context *ctdb, int argc, const char **argv) { struct ctdb_tcp_connection t; TDB_DATA data; int ret; assert_single_node_only(); if (argc < 2) { usage(); } if (parse_ip_port(argv[0], &t.src_addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0])); return -1; } if (parse_ip_port(argv[1], &t.dst_addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[1])); return -1; } data.dptr = (uint8_t *)&t; data.dsize = sizeof(t); /* tell all nodes about this tcp connection */ ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE, 0, data, ctdb, NULL, NULL, NULL, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to add tickle\n")); return -1; } return 0; } /* delete a tickle from a node */ static int control_del_tickle(struct ctdb_context *ctdb, int argc, const char **argv) { struct ctdb_tcp_connection t; TDB_DATA data; int ret; assert_single_node_only(); if (argc < 2) { usage(); } if (parse_ip_port(argv[0], &t.src_addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0])); return -1; } if (parse_ip_port(argv[1], &t.dst_addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[1])); return -1; } data.dptr = (uint8_t *)&t; data.dsize = sizeof(t); /* tell all nodes about this tcp connection */ ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_TCP_REMOVE, 0, data, ctdb, NULL, NULL, NULL, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to remove tickle\n")); return -1; } return 0; } /* get a list of all tickles for this pnn */ static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char **argv) { struct ctdb_control_tcp_tickle_list *list; ctdb_sock_addr addr; int i, ret; unsigned port = 0; assert_single_node_only(); if (argc < 1) { usage(); } if (argc == 2) { port = atoi(argv[1]); } if (parse_ip(argv[0], NULL, 0, &addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0])); return -1; } ret = ctdb_ctrl_get_tcp_tickles(ctdb, TIMELIMIT(), options.pnn, ctdb, &addr, &list); if (ret == -1) { DEBUG(DEBUG_ERR, ("Unable to list tickles\n")); return -1; } if (options.machinereadable){ printf(":source ip:port:destination ip:port:\n"); for (i=0;itickles.num;i++) { if (port && port != ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)) { continue; } printf(":%s:%u", ctdb_addr_to_str(&list->tickles.connections[i].src_addr), ntohs(list->tickles.connections[i].src_addr.ip.sin_port)); printf(":%s:%u:\n", ctdb_addr_to_str(&list->tickles.connections[i].dst_addr), ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)); } } else { printf("Tickles for ip:%s\n", ctdb_addr_to_str(&list->addr)); printf("Num tickles:%u\n", list->tickles.num); for (i=0;itickles.num;i++) { if (port && port != ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)) { continue; } printf("SRC: %s:%u ", ctdb_addr_to_str(&list->tickles.connections[i].src_addr), ntohs(list->tickles.connections[i].src_addr.ip.sin_port)); printf("DST: %s:%u\n", ctdb_addr_to_str(&list->tickles.connections[i].dst_addr), ntohs(list->tickles.connections[i].dst_addr.ip.sin_port)); } } talloc_free(list); return 0; } static int move_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr, uint32_t pnn) { struct ctdb_all_public_ips *ips; struct ctdb_public_ip ip; int i, ret; uint32_t *nodes; uint32_t disable_time; TDB_DATA data; struct ctdb_node_map *nodemap=NULL; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); disable_time = 30; data.dptr = (uint8_t*)&disable_time; data.dsize = sizeof(disable_time); ret = ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_DISABLE_IP_CHECK, data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to send message to disable ipcheck\n")); return -1; } /* read the public ip list from the node */ ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), pnn, ctdb, &ips); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", pnn)); talloc_free(tmp_ctx); return -1; } for (i=0;inum;i++) { if (ctdb_same_ip(addr, &ips->ips[i].addr)) { break; } } if (i==ips->num) { DEBUG(DEBUG_ERR, ("Node %u can not host ip address '%s'\n", pnn, ctdb_addr_to_str(addr))); talloc_free(tmp_ctx); return -1; } ip.pnn = pnn; ip.addr = *addr; data.dptr = (uint8_t *)&ip; data.dsize = sizeof(ip); ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } nodes = list_of_nodes(ctdb, nodemap, tmp_ctx, NODE_FLAGS_INACTIVE, pnn); ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_RELEASE_IP, nodes, 0, LONGTIMELIMIT(), false, data, NULL, NULL, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to release IP on nodes\n")); talloc_free(tmp_ctx); return -1; } ret = ctdb_ctrl_takeover_ip(ctdb, LONGTIMELIMIT(), pnn, &ip); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to take over IP on node %d\n", pnn)); talloc_free(tmp_ctx); return -1; } /* update the recovery daemon so it now knows to expect the new node assignment for this ip. */ ret = ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_RECD_UPDATE_IP, data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to send message to update the ip on the recovery master.\n")); return -1; } talloc_free(tmp_ctx); return 0; } /* * scans all other nodes and returns a pnn for another node that can host this * ip address or -1 */ static int find_other_host_for_public_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_all_public_ips *ips; struct ctdb_node_map *nodemap=NULL; int i, j, ret; ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } for(i=0;inum;i++){ if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { continue; } if (nodemap->nodes[i].pnn == options.pnn) { continue; } /* read the public ip list from this node */ ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", nodemap->nodes[i].pnn)); return -1; } for (j=0;jnum;j++) { if (ctdb_same_ip(addr, &ips->ips[j].addr)) { talloc_free(tmp_ctx); return nodemap->nodes[i].pnn; } } talloc_free(ips); } talloc_free(tmp_ctx); return -1; } /* If pnn is -1 then try to find a node to move IP to... */ static bool try_moveip(struct ctdb_context *ctdb, ctdb_sock_addr *addr, uint32_t pnn) { bool pnn_specified = (pnn == -1 ? false : true); int retries = 0; while (retries < 5) { if (!pnn_specified) { pnn = find_other_host_for_public_ip(ctdb, addr); if (pnn == -1) { return false; } DEBUG(DEBUG_NOTICE, ("Trying to move public IP to node %u\n", pnn)); } if (move_ip(ctdb, addr, pnn) == 0) { return true; } sleep(3); retries++; } return false; } /* move/failover an ip address to a specific node */ static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t pnn; ctdb_sock_addr addr; assert_single_node_only(); if (argc < 2) { usage(); return -1; } if (parse_ip(argv[0], NULL, 0, &addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0])); return -1; } if (sscanf(argv[1], "%u", &pnn) != 1) { DEBUG(DEBUG_ERR, ("Badly formed pnn\n")); return -1; } if (!try_moveip(ctdb, &addr, pnn)) { DEBUG(DEBUG_ERR,("Failed to move IP to node %d.\n", pnn)); return -1; } return 0; } static int rebalance_node(struct ctdb_context *ctdb, uint32_t pnn) { TDB_DATA data; data.dptr = (uint8_t *)&pnn; data.dsize = sizeof(uint32_t); if (ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_REBALANCE_NODE, data) != 0) { DEBUG(DEBUG_ERR, ("Failed to send message to force node %u to be a rebalancing target\n", pnn)); return -1; } return 0; } /* rebalance a node by setting it to allow failback and triggering a takeover run */ static int control_rebalancenode(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); uint32_t *nodes; uint32_t pnn_mode; int i, ret; assert_single_node_only(); if (argc > 1) { usage(); } /* Determine the nodes where IPs need to be reloaded */ if (!parse_nodestring(ctdb, tmp_ctx, argc == 1 ? argv[0] : NULL, options.pnn, true, &nodes, &pnn_mode)) { ret = -1; goto done; } for (i = 0; i < talloc_array_length(nodes); i++) { if (!rebalance_node(ctdb, nodes[i])) { ret = -1; } } done: talloc_free(tmp_ctx); return ret; } static int rebalance_ip(struct ctdb_context *ctdb, ctdb_sock_addr *addr) { struct ctdb_public_ip ip; int ret; uint32_t *nodes; uint32_t disable_time; TDB_DATA data; struct ctdb_node_map *nodemap=NULL; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); disable_time = 30; data.dptr = (uint8_t*)&disable_time; data.dsize = sizeof(disable_time); ret = ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, CTDB_SRVID_DISABLE_IP_CHECK, data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to send message to disable ipcheck\n")); return -1; } ip.pnn = -1; ip.addr = *addr; data.dptr = (uint8_t *)&ip; data.dsize = sizeof(ip); ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_RELEASE_IP, nodes, 0, LONGTIMELIMIT(), false, data, NULL, NULL, NULL); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to release IP on nodes\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } /* release an ip form all nodes and have it re-assigned by recd */ static int control_rebalanceip(struct ctdb_context *ctdb, int argc, const char **argv) { ctdb_sock_addr addr; assert_single_node_only(); if (argc < 1) { usage(); return -1; } if (parse_ip(argv[0], NULL, 0, &addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0])); return -1; } if (rebalance_ip(ctdb, &addr) != 0) { DEBUG(DEBUG_ERR,("Error when trying to reassign ip\n")); return -1; } return 0; } static int getips_store_callback(void *param, void *data) { struct ctdb_public_ip *node_ip = (struct ctdb_public_ip *)data; struct ctdb_all_public_ips *ips = param; int i; i = ips->num++; ips->ips[i].pnn = node_ip->pnn; ips->ips[i].addr = node_ip->addr; return 0; } static int getips_count_callback(void *param, void *data) { uint32_t *count = param; (*count)++; return 0; } #define IP_KEYLEN 4 static uint32_t *ip_key(ctdb_sock_addr *ip) { static uint32_t key[IP_KEYLEN]; bzero(key, sizeof(key)); switch (ip->sa.sa_family) { case AF_INET: key[0] = ip->ip.sin_addr.s_addr; break; case AF_INET6: { uint32_t *s6_a32 = (uint32_t *)&(ip->ip6.sin6_addr.s6_addr); key[0] = s6_a32[3]; key[1] = s6_a32[2]; key[2] = s6_a32[1]; key[3] = s6_a32[0]; break; } default: DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", ip->sa.sa_family)); return key; } return key; } static void *add_ip_callback(void *parm, void *data) { return parm; } static int control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struct ctdb_all_public_ips **ips) { struct ctdb_all_public_ips *tmp_ips; struct ctdb_node_map *nodemap=NULL; trbt_tree_t *ip_tree; int i, j, len, ret; uint32_t count; ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); return ret; } ip_tree = trbt_create(tmp_ctx, 0); for(i=0;inum;i++){ if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) { continue; } if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) { continue; } /* read the public ip list from this node */ ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &tmp_ips); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", nodemap->nodes[i].pnn)); return -1; } for (j=0; jnum;j++) { struct ctdb_public_ip *node_ip; node_ip = talloc(tmp_ctx, struct ctdb_public_ip); node_ip->pnn = tmp_ips->ips[j].pnn; node_ip->addr = tmp_ips->ips[j].addr; trbt_insertarray32_callback(ip_tree, IP_KEYLEN, ip_key(&tmp_ips->ips[j].addr), add_ip_callback, node_ip); } talloc_free(tmp_ips); } /* traverse */ count = 0; trbt_traversearray32(ip_tree, IP_KEYLEN, getips_count_callback, &count); len = offsetof(struct ctdb_all_public_ips, ips) + count*sizeof(struct ctdb_public_ip); tmp_ips = talloc_zero_size(tmp_ctx, len); trbt_traversearray32(ip_tree, IP_KEYLEN, getips_store_callback, tmp_ips); *ips = tmp_ips; return 0; } static void ctdb_every_second(struct event_context *ev, struct timed_event *te, struct timeval t, void *p) { struct ctdb_context *ctdb = talloc_get_type(p, struct ctdb_context); event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), ctdb_every_second, ctdb); } struct srvid_reply_handler_data { bool done; bool wait_for_all; uint32_t *nodes; const char *srvid_str; }; static void srvid_broadcast_reply_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *private_data) { struct srvid_reply_handler_data *d = (struct srvid_reply_handler_data *)private_data; int i; int32_t ret; if (data.dsize != sizeof(ret)) { DEBUG(DEBUG_ERR, (__location__ " Wrong reply size\n")); return; } /* ret will be a PNN (i.e. >=0) on success, or negative on error */ ret = *(int32_t *)data.dptr; if (ret < 0) { DEBUG(DEBUG_ERR, ("%s failed with result %d\n", d->srvid_str, ret)); return; } if (!d->wait_for_all) { d->done = true; return; } /* Wait for all replies */ d->done = true; for (i = 0; i < talloc_array_length(d->nodes); i++) { if (d->nodes[i] == ret) { DEBUG(DEBUG_INFO, ("%s reply received from node %u\n", d->srvid_str, ret)); d->nodes[i] = -1; } if (d->nodes[i] != -1) { /* Found a node that hasn't yet replied */ d->done = false; } } } /* Broadcast the given SRVID to all connected nodes. Wait for 1 reply * or replies from all connected nodes. arg is the data argument to * pass in the srvid_request structure - pass 0 if this isn't needed. */ static int srvid_broadcast(struct ctdb_context *ctdb, uint64_t srvid, uint32_t *arg, const char *srvid_str, bool wait_for_all) { int ret; TDB_DATA data; uint32_t pnn; uint64_t reply_srvid; struct srvid_request request; struct srvid_request_data request_data; struct srvid_reply_handler_data reply_data; struct timeval tv; ZERO_STRUCT(request); /* Time ticks to enable timeouts to be processed */ event_add_timed(ctdb->ev, ctdb, timeval_current_ofs(1, 0), ctdb_every_second, ctdb); pnn = ctdb_get_pnn(ctdb); reply_srvid = getpid(); if (arg == NULL) { request.pnn = pnn; request.srvid = reply_srvid; data.dptr = (uint8_t *)&request; data.dsize = sizeof(request); } else { request_data.pnn = pnn; request_data.srvid = reply_srvid; request_data.data = *arg; data.dptr = (uint8_t *)&request_data; data.dsize = sizeof(request_data); } /* Register message port for reply from recovery master */ ctdb_client_set_message_handler(ctdb, reply_srvid, srvid_broadcast_reply_handler, &reply_data); reply_data.wait_for_all = wait_for_all; reply_data.nodes = NULL; reply_data.srvid_str = srvid_str; again: reply_data.done = false; if (wait_for_all) { struct ctdb_node_map *nodemap; ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from current node, try again\n")); sleep(1); goto again; } if (reply_data.nodes != NULL) { talloc_free(reply_data.nodes); } reply_data.nodes = list_of_connected_nodes(ctdb, nodemap, NULL, true); talloc_free(nodemap); } /* Send to all connected nodes. Only recmaster replies */ ret = ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, srvid, data); if (ret != 0) { /* This can only happen if the socket is closed and * there's no way to recover from that, so don't try * again. */ DEBUG(DEBUG_ERR, ("Failed to send %s request to connected nodes\n", srvid_str)); return -1; } tv = timeval_current(); /* This loop terminates the reply is received */ while (timeval_elapsed(&tv) < 5.0 && !reply_data.done) { event_loop_once(ctdb->ev); } if (!reply_data.done) { DEBUG(DEBUG_NOTICE, ("Still waiting for confirmation of %s\n", srvid_str)); sleep(1); goto again; } ctdb_client_remove_message_handler(ctdb, reply_srvid, &reply_data); talloc_free(reply_data.nodes); return 0; } static int ipreallocate(struct ctdb_context *ctdb) { return srvid_broadcast(ctdb, CTDB_SRVID_TAKEOVER_RUN, NULL, "IP reallocation", false); } static int control_ipreallocate(struct ctdb_context *ctdb, int argc, const char **argv) { return ipreallocate(ctdb); } /* add a public ip address to a node */ static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv) { int i, ret; int len, retries = 0; unsigned mask; ctdb_sock_addr addr; struct ctdb_control_ip_iface *pub; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_all_public_ips *ips; if (argc != 2) { talloc_free(tmp_ctx); usage(); } if (!parse_ip_mask(argv[0], argv[1], &addr, &mask)) { DEBUG(DEBUG_ERR, ("Badly formed ip/mask : %s\n", argv[0])); talloc_free(tmp_ctx); return -1; } /* read the public ip list from the node */ ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &ips); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } for (i=0;inum;i++) { if (ctdb_same_ip(&addr, &ips->ips[i].addr)) { DEBUG(DEBUG_ERR,("Can not add ip to node. Node already hosts this ip\n")); return 0; } } /* Dont timeout. This command waits for an ip reallocation which sometimes can take wuite a while if there has been a recent recovery */ alarm(0); len = offsetof(struct ctdb_control_ip_iface, iface) + strlen(argv[1]) + 1; pub = talloc_size(tmp_ctx, len); CTDB_NO_MEMORY(ctdb, pub); pub->addr = addr; pub->mask = mask; pub->len = strlen(argv[1])+1; memcpy(&pub->iface[0], argv[1], strlen(argv[1])+1); do { ret = ctdb_ctrl_add_public_ip(ctdb, TIMELIMIT(), options.pnn, pub); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to add public ip to node %u. Wait 3 seconds and try again.\n", options.pnn)); sleep(3); retries++; } } while (retries < 5 && ret != 0); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to add public ip to node %u. Giving up.\n", options.pnn)); talloc_free(tmp_ctx); return ret; } if (rebalance_node(ctdb, options.pnn) != 0) { DEBUG(DEBUG_ERR,("Error when trying to rebalance node\n")); return ret; } talloc_free(tmp_ctx); return 0; } /* add a public ip address to a node */ static int control_ipiface(struct ctdb_context *ctdb, int argc, const char **argv) { ctdb_sock_addr addr; if (argc != 1) { usage(); } if (!parse_ip(argv[0], NULL, 0, &addr)) { printf("Badly formed ip : %s\n", argv[0]); return -1; } printf("IP on interface %s\n", ctdb_sys_find_ifname(&addr)); return 0; } static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv); static int control_delip_all(struct ctdb_context *ctdb, int argc, const char **argv, ctdb_sock_addr *addr) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_node_map *nodemap=NULL; struct ctdb_all_public_ips *ips; int ret, i, j; ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from current node\n")); return ret; } /* remove it from the nodes that are not hosting the ip currently */ for(i=0;inum;i++){ if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { continue; } ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %d\n", nodemap->nodes[i].pnn)); continue; } for (j=0;jnum;j++) { if (ctdb_same_ip(addr, &ips->ips[j].addr)) { break; } } if (j==ips->num) { continue; } if (ips->ips[j].pnn == nodemap->nodes[i].pnn) { continue; } options.pnn = nodemap->nodes[i].pnn; control_delip(ctdb, argc, argv); } /* remove it from every node (also the one hosting it) */ for(i=0;inum;i++){ if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { continue; } ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &ips); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %d\n", nodemap->nodes[i].pnn)); continue; } for (j=0;jnum;j++) { if (ctdb_same_ip(addr, &ips->ips[j].addr)) { break; } } if (j==ips->num) { continue; } options.pnn = nodemap->nodes[i].pnn; control_delip(ctdb, argc, argv); } talloc_free(tmp_ctx); return 0; } /* delete a public ip address from a node */ static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv) { int i, ret; ctdb_sock_addr addr; struct ctdb_control_ip_iface pub; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_all_public_ips *ips; if (argc != 1) { talloc_free(tmp_ctx); usage(); } if (parse_ip(argv[0], NULL, 0, &addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0])); return -1; } if (options.pnn == CTDB_BROADCAST_ALL) { return control_delip_all(ctdb, argc, argv, &addr); } pub.addr = addr; pub.mask = 0; pub.len = 0; ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &ips); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ip list from cluster\n")); talloc_free(tmp_ctx); return ret; } for (i=0;inum;i++) { if (ctdb_same_ip(&addr, &ips->ips[i].addr)) { break; } } if (i==ips->num) { DEBUG(DEBUG_ERR, ("This node does not support this public address '%s'\n", ctdb_addr_to_str(&addr))); talloc_free(tmp_ctx); return -1; } /* This is an optimisation. If this node is hosting the IP * then try to move it somewhere else without invoking a full * takeover run. We don't care if this doesn't work! */ if (ips->ips[i].pnn == options.pnn) { (void) try_moveip(ctdb, &addr, -1); } ret = ctdb_ctrl_del_public_ip(ctdb, TIMELIMIT(), options.pnn, &pub); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to del public ip from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } talloc_free(tmp_ctx); return 0; } static int kill_tcp_from_file(struct ctdb_context *ctdb, int argc, const char **argv) { struct ctdb_control_killtcp *killtcp; int max_entries, current, i; struct timeval timeout; char line[128], src[128], dst[128]; int linenum; TDB_DATA data; struct client_async_data *async_data; struct ctdb_client_control_state *state; if (argc != 0) { usage(); } linenum = 1; killtcp = NULL; max_entries = 0; current = 0; while (!feof(stdin)) { if (fgets(line, sizeof(line), stdin) == NULL) { continue; } /* Silently skip empty lines */ if (line[0] == '\n') { continue; } if (sscanf(line, "%s %s\n", src, dst) != 2) { DEBUG(DEBUG_ERR, ("Bad line [%d]: '%s'\n", linenum, line)); talloc_free(killtcp); return -1; } if (current >= max_entries) { max_entries += 1024; killtcp = talloc_realloc(ctdb, killtcp, struct ctdb_control_killtcp, max_entries); CTDB_NO_MEMORY(ctdb, killtcp); } if (!parse_ip_port(src, &killtcp[current].src_addr)) { DEBUG(DEBUG_ERR, ("Bad IP:port on line [%d]: '%s'\n", linenum, src)); talloc_free(killtcp); return -1; } if (!parse_ip_port(dst, &killtcp[current].dst_addr)) { DEBUG(DEBUG_ERR, ("Bad IP:port on line [%d]: '%s'\n", linenum, dst)); talloc_free(killtcp); return -1; } current++; } async_data = talloc_zero(ctdb, struct client_async_data); if (async_data == NULL) { talloc_free(killtcp); return -1; } for (i = 0; i < current; i++) { data.dsize = sizeof(struct ctdb_control_killtcp); data.dptr = (unsigned char *)&killtcp[i]; timeout = TIMELIMIT(); state = ctdb_control_send(ctdb, options.pnn, 0, CTDB_CONTROL_KILL_TCP, 0, data, async_data, &timeout, NULL); if (state == NULL) { DEBUG(DEBUG_ERR, ("Failed to call async killtcp control to node %u\n", options.pnn)); talloc_free(killtcp); return -1; } ctdb_client_async_add(async_data, state); } if (ctdb_client_async_wait(ctdb, async_data) != 0) { DEBUG(DEBUG_ERR,("killtcp failed\n")); talloc_free(killtcp); return -1; } talloc_free(killtcp); return 0; } /* kill a tcp connection */ static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; struct ctdb_control_killtcp killtcp; assert_single_node_only(); if (argc == 0) { return kill_tcp_from_file(ctdb, argc, argv); } if (argc < 2) { usage(); } if (!parse_ip_port(argv[0], &killtcp.src_addr)) { DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[0])); return -1; } if (!parse_ip_port(argv[1], &killtcp.dst_addr)) { DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[1])); return -1; } ret = ctdb_ctrl_killtcp(ctdb, TIMELIMIT(), options.pnn, &killtcp); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to killtcp from node %u\n", options.pnn)); return ret; } return 0; } /* send a gratious arp */ static int control_gratious_arp(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; ctdb_sock_addr addr; assert_single_node_only(); if (argc < 2) { usage(); } if (!parse_ip(argv[0], NULL, 0, &addr)) { DEBUG(DEBUG_ERR, ("Bad IP '%s'\n", argv[0])); return -1; } ret = ctdb_ctrl_gratious_arp(ctdb, TIMELIMIT(), options.pnn, &addr, argv[1]); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to send gratious_arp from node %u\n", options.pnn)); return ret; } return 0; } /* register a server id */ static int regsrvid(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; struct ctdb_server_id server_id; if (argc < 3) { usage(); } server_id.pnn = strtoul(argv[0], NULL, 0); server_id.type = strtoul(argv[1], NULL, 0); server_id.server_id = strtoul(argv[2], NULL, 0); ret = ctdb_ctrl_register_server_id(ctdb, TIMELIMIT(), &server_id); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to register server_id from node %u\n", options.pnn)); return ret; } DEBUG(DEBUG_ERR,("Srvid registered. Sleeping for 999 seconds\n")); sleep(999); return -1; } /* unregister a server id */ static int unregsrvid(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; struct ctdb_server_id server_id; if (argc < 3) { usage(); } server_id.pnn = strtoul(argv[0], NULL, 0); server_id.type = strtoul(argv[1], NULL, 0); server_id.server_id = strtoul(argv[2], NULL, 0); ret = ctdb_ctrl_unregister_server_id(ctdb, TIMELIMIT(), &server_id); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to unregister server_id from node %u\n", options.pnn)); return ret; } return -1; } /* check if a server id exists */ static int chksrvid(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t status; int ret; struct ctdb_server_id server_id; if (argc < 3) { usage(); } server_id.pnn = strtoul(argv[0], NULL, 0); server_id.type = strtoul(argv[1], NULL, 0); server_id.server_id = strtoul(argv[2], NULL, 0); ret = ctdb_ctrl_check_server_id(ctdb, TIMELIMIT(), options.pnn, &server_id, &status); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to check server_id from node %u\n", options.pnn)); return ret; } if (status) { printf("Server id %d:%d:%d EXISTS\n", server_id.pnn, server_id.type, server_id.server_id); } else { printf("Server id %d:%d:%d does NOT exist\n", server_id.pnn, server_id.type, server_id.server_id); } return 0; } /* get a list of all server ids that are registered on a node */ static int getsrvids(struct ctdb_context *ctdb, int argc, const char **argv) { int i, ret; struct ctdb_server_id_list *server_ids; ret = ctdb_ctrl_get_server_id_list(ctdb, ctdb, TIMELIMIT(), options.pnn, &server_ids); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get server_id list from node %u\n", options.pnn)); return ret; } for (i=0; inum; i++) { printf("Server id %d:%d:%d\n", server_ids->server_ids[i].pnn, server_ids->server_ids[i].type, server_ids->server_ids[i].server_id); } return -1; } /* check if a server id exists */ static int check_srvids(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(NULL); uint64_t *ids; uint8_t *result; int i; if (argc < 1) { talloc_free(tmp_ctx); usage(); } ids = talloc_array(tmp_ctx, uint64_t, argc); result = talloc_array(tmp_ctx, uint8_t, argc); for (i = 0; i < argc; i++) { ids[i] = strtoull(argv[i], NULL, 0); } if (!ctdb_client_check_message_handlers(ctdb, ids, argc, result)) { DEBUG(DEBUG_ERR, ("Unable to check server_id from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } for (i=0; i < argc; i++) { printf("Server id %d:%llu %s\n", options.pnn, (long long)ids[i], result[i] ? "exists" : "does not exist"); } talloc_free(tmp_ctx); return 0; } /* send a tcp tickle ack */ static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; ctdb_sock_addr src, dst; if (argc < 2) { usage(); } if (!parse_ip_port(argv[0], &src)) { DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[0])); return -1; } if (!parse_ip_port(argv[1], &dst)) { DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[1])); return -1; } ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0); if (ret==0) { return 0; } DEBUG(DEBUG_ERR, ("Error while sending tickle ack\n")); return -1; } /* display public ip status */ static int control_ip(struct ctdb_context *ctdb, int argc, const char **argv) { int i, ret; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_all_public_ips *ips; if (options.pnn == CTDB_BROADCAST_ALL) { /* read the list of public ips from all nodes */ ret = control_get_all_public_ips(ctdb, tmp_ctx, &ips); } else { /* read the public ip list from this node */ ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &ips); } if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ips from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } if (options.machinereadable){ printf(":Public IP:Node:"); if (options.verbose){ printf("ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:"); } printf("\n"); } else { if (options.pnn == CTDB_BROADCAST_ALL) { printf("Public IPs on ALL nodes\n"); } else { printf("Public IPs on node %u\n", options.pnn); } } for (i=1;i<=ips->num;i++) { struct ctdb_control_public_ip_info *info = NULL; int32_t pnn; char *aciface = NULL; char *avifaces = NULL; char *cifaces = NULL; if (options.pnn == CTDB_BROADCAST_ALL) { pnn = ips->ips[ips->num-i].pnn; } else { pnn = options.pnn; } if (pnn != -1) { ret = ctdb_ctrl_get_public_ip_info(ctdb, TIMELIMIT(), pnn, ctdb, &ips->ips[ips->num-i].addr, &info); } else { ret = -1; } if (ret == 0) { int j; for (j=0; j < info->num; j++) { if (cifaces == NULL) { cifaces = talloc_strdup(info, info->ifaces[j].name); } else { cifaces = talloc_asprintf_append(cifaces, ",%s", info->ifaces[j].name); } if (info->active_idx == j) { aciface = info->ifaces[j].name; } if (info->ifaces[j].link_state == 0) { continue; } if (avifaces == NULL) { avifaces = talloc_strdup(info, info->ifaces[j].name); } else { avifaces = talloc_asprintf_append(avifaces, ",%s", info->ifaces[j].name); } } } if (options.machinereadable){ printf(":%s:%d:", ctdb_addr_to_str(&ips->ips[ips->num-i].addr), ips->ips[ips->num-i].pnn); if (options.verbose){ printf("%s:%s:%s:", aciface?aciface:"", avifaces?avifaces:"", cifaces?cifaces:""); } printf("\n"); } else { if (options.verbose) { printf("%s node[%d] active[%s] available[%s] configured[%s]\n", ctdb_addr_to_str(&ips->ips[ips->num-i].addr), ips->ips[ips->num-i].pnn, aciface?aciface:"", avifaces?avifaces:"", cifaces?cifaces:""); } else { printf("%s %d\n", ctdb_addr_to_str(&ips->ips[ips->num-i].addr), ips->ips[ips->num-i].pnn); } } talloc_free(info); } talloc_free(tmp_ctx); return 0; } /* public ip info */ static int control_ipinfo(struct ctdb_context *ctdb, int argc, const char **argv) { int i, ret; ctdb_sock_addr addr; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_control_public_ip_info *info; if (argc != 1) { talloc_free(tmp_ctx); usage(); } if (parse_ip(argv[0], NULL, 0, &addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0])); return -1; } /* read the public ip info from this node */ ret = ctdb_ctrl_get_public_ip_info(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &addr, &info); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get public ip[%s]info from node %u\n", argv[0], options.pnn)); talloc_free(tmp_ctx); return ret; } printf("Public IP[%s] info on node %u\n", ctdb_addr_to_str(&info->ip.addr), options.pnn); printf("IP:%s\nCurrentNode:%d\nNumInterfaces:%u\n", ctdb_addr_to_str(&info->ip.addr), info->ip.pnn, info->num); for (i=0; inum; i++) { info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0'; printf("Interface[%u]: Name:%s Link:%s References:%u%s\n", i+1, info->ifaces[i].name, info->ifaces[i].link_state?"up":"down", (unsigned int)info->ifaces[i].references, (i==info->active_idx)?" (active)":""); } talloc_free(tmp_ctx); return 0; } /* display interfaces status */ static int control_ifaces(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); int i; struct ctdb_control_get_ifaces *ifaces; int ret; /* read the public ip list from this node */ ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &ifaces); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get interfaces from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } if (options.machinereadable){ printf(":Name:LinkStatus:References:\n"); } else { printf("Interfaces on node %u\n", options.pnn); } for (i=0; inum; i++) { if (options.machinereadable){ printf(":%s:%s:%u\n", ifaces->ifaces[i].name, ifaces->ifaces[i].link_state?"1":"0", (unsigned int)ifaces->ifaces[i].references); } else { printf("name:%s link:%s references:%u\n", ifaces->ifaces[i].name, ifaces->ifaces[i].link_state?"up":"down", (unsigned int)ifaces->ifaces[i].references); } } talloc_free(tmp_ctx); return 0; } /* set link status of an interface */ static int control_setifacelink(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_control_iface_info info; ZERO_STRUCT(info); if (argc != 2) { usage(); } if (strlen(argv[0]) > CTDB_IFACE_SIZE) { DEBUG(DEBUG_ERR, ("interfaces name '%s' too long\n", argv[0])); talloc_free(tmp_ctx); return -1; } strcpy(info.name, argv[0]); if (strcmp(argv[1], "up") == 0) { info.link_state = 1; } else if (strcmp(argv[1], "down") == 0) { info.link_state = 0; } else { DEBUG(DEBUG_ERR, ("link state invalid '%s' should be 'up' or 'down'\n", argv[1])); talloc_free(tmp_ctx); return -1; } /* read the public ip list from this node */ ret = ctdb_ctrl_set_iface_link(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &info); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to set link state for interfaces %s node %u\n", argv[0], options.pnn)); talloc_free(tmp_ctx); return ret; } talloc_free(tmp_ctx); return 0; } /* display pid of a ctdb daemon */ static int control_getpid(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t pid; int ret; ret = ctdb_ctrl_getpid(ctdb, TIMELIMIT(), options.pnn, &pid); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get daemon pid from node %u\n", options.pnn)); return ret; } printf("Pid:%d\n", pid); return 0; } typedef bool update_flags_handler_t(struct ctdb_context *ctdb, void *data); static int update_flags_and_ipreallocate(struct ctdb_context *ctdb, void *data, update_flags_handler_t handler, uint32_t flag, const char *desc, bool set_flag) { struct ctdb_node_map *nodemap = NULL; bool flag_is_set; int ret; /* Check if the node is already in the desired state */ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n")); exit(10); } flag_is_set = nodemap->nodes[options.pnn].flags & flag; if (set_flag == flag_is_set) { DEBUG(DEBUG_NOTICE, ("Node %d is %s %s\n", options.pnn, (set_flag ? "already" : "not"), desc)); return 0; } do { if (!handler(ctdb, data)) { DEBUG(DEBUG_WARNING, ("Failed to send control to set state %s on node %u, try again\n", desc, options.pnn)); } sleep(1); /* Read the nodemap and verify the change took effect. * Even if the above control/hanlder timed out then it * could still have worked! */ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap); if (ret != 0) { DEBUG(DEBUG_WARNING, ("Unable to get nodemap from local node, try again\n")); } flag_is_set = nodemap->nodes[options.pnn].flags & flag; } while (nodemap == NULL || (set_flag != flag_is_set)); return ipreallocate(ctdb); } /* Administratively disable a node */ static bool update_flags_disabled(struct ctdb_context *ctdb, void *data) { int ret; ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn, NODE_FLAGS_PERMANENTLY_DISABLED, 0); return ret == 0; } static int control_disable(struct ctdb_context *ctdb, int argc, const char **argv) { return update_flags_and_ipreallocate(ctdb, NULL, update_flags_disabled, NODE_FLAGS_PERMANENTLY_DISABLED, "disabled", true /* set_flag*/); } /* Administratively re-enable a node */ static bool update_flags_not_disabled(struct ctdb_context *ctdb, void *data) { int ret; ret = ctdb_ctrl_modflags(ctdb, TIMELIMIT(), options.pnn, 0, NODE_FLAGS_PERMANENTLY_DISABLED); return ret == 0; } static int control_enable(struct ctdb_context *ctdb, int argc, const char **argv) { return update_flags_and_ipreallocate(ctdb, NULL, update_flags_not_disabled, NODE_FLAGS_PERMANENTLY_DISABLED, "disabled", false /* set_flag*/); } /* Stop a node */ static bool update_flags_stopped(struct ctdb_context *ctdb, void *data) { int ret; ret = ctdb_ctrl_stop_node(ctdb, TIMELIMIT(), options.pnn); return ret == 0; } static int control_stop(struct ctdb_context *ctdb, int argc, const char **argv) { return update_flags_and_ipreallocate(ctdb, NULL, update_flags_stopped, NODE_FLAGS_STOPPED, "stopped", true /* set_flag*/); } /* Continue a stopped node */ static bool update_flags_not_stopped(struct ctdb_context *ctdb, void *data) { int ret; ret = ctdb_ctrl_continue_node(ctdb, TIMELIMIT(), options.pnn); return ret == 0; } static int control_continue(struct ctdb_context *ctdb, int argc, const char **argv) { return update_flags_and_ipreallocate(ctdb, NULL, update_flags_not_stopped, NODE_FLAGS_STOPPED, "stopped", false /* set_flag */); } static uint32_t get_generation(struct ctdb_context *ctdb) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_vnn_map *vnnmap=NULL; int ret; uint32_t generation; /* wait until the recmaster is not in recovery mode */ while (1) { uint32_t recmode, recmaster; if (vnnmap != NULL) { talloc_free(vnnmap); vnnmap = NULL; } /* get the recmaster */ ret = ctdb_ctrl_getrecmaster(ctdb, tmp_ctx, TIMELIMIT(), CTDB_CURRENT_NODE, &recmaster); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get recmaster from node %u\n", options.pnn)); talloc_free(tmp_ctx); exit(10); } /* get recovery mode */ ret = ctdb_ctrl_getrecmode(ctdb, tmp_ctx, TIMELIMIT(), recmaster, &recmode); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get recmode from node %u\n", options.pnn)); talloc_free(tmp_ctx); exit(10); } /* get the current generation number */ ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), recmaster, tmp_ctx, &vnnmap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get vnnmap from recmaster (%u)\n", recmaster)); talloc_free(tmp_ctx); exit(10); } if ((recmode == CTDB_RECOVERY_NORMAL) && (vnnmap->generation != 1)) { generation = vnnmap->generation; talloc_free(tmp_ctx); return generation; } sleep(1); } } /* Ban a node */ static bool update_state_banned(struct ctdb_context *ctdb, void *data) { struct ctdb_ban_time *bantime = (struct ctdb_ban_time *)data; int ret; ret = ctdb_ctrl_set_ban(ctdb, TIMELIMIT(), options.pnn, bantime); return ret == 0; } static int control_ban(struct ctdb_context *ctdb, int argc, const char **argv) { struct ctdb_ban_time bantime; if (argc < 1) { usage(); } bantime.pnn = options.pnn; bantime.time = strtoul(argv[0], NULL, 0); if (bantime.time == 0) { DEBUG(DEBUG_ERR, ("Invalid ban time specified - must be >0\n")); return -1; } return update_flags_and_ipreallocate(ctdb, &bantime, update_state_banned, NODE_FLAGS_BANNED, "banned", true /* set_flag*/); } /* Unban a node */ static int control_unban(struct ctdb_context *ctdb, int argc, const char **argv) { struct ctdb_ban_time bantime; bantime.pnn = options.pnn; bantime.time = 0; return update_flags_and_ipreallocate(ctdb, &bantime, update_state_banned, NODE_FLAGS_BANNED, "banned", false /* set_flag*/); } /* show ban information for a node */ static int control_showban(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; struct ctdb_node_map *nodemap=NULL; struct ctdb_ban_time *bantime; /* verify the node exists */ ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n")); return ret; } ret = ctdb_ctrl_get_ban(ctdb, TIMELIMIT(), options.pnn, ctdb, &bantime); if (ret != 0) { DEBUG(DEBUG_ERR,("Showing ban info for node %d failed.\n", options.pnn)); return -1; } if (bantime->time == 0) { printf("Node %u is not banned\n", bantime->pnn); } else { printf("Node %u is banned, %d seconds remaining\n", bantime->pnn, bantime->time); } return 0; } /* shutdown a daemon */ static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; ret = ctdb_ctrl_shutdown(ctdb, TIMELIMIT(), options.pnn); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to shutdown node %u\n", options.pnn)); return ret; } return 0; } /* trigger a recovery */ static int control_recover(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; uint32_t generation, next_generation; bool force; /* "force" option ignores freeze failure and forces recovery */ force = (argc == 1) && (strcasecmp(argv[0], "force") == 0); /* record the current generation number */ generation = get_generation(ctdb); ret = ctdb_ctrl_freeze_priority(ctdb, TIMELIMIT(), options.pnn, 1); if (ret != 0) { if (!force) { DEBUG(DEBUG_ERR, ("Unable to freeze node\n")); return ret; } DEBUG(DEBUG_WARNING, ("Unable to freeze node but proceeding because \"force\" option given\n")); } ret = ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to set recovery mode\n")); return ret; } /* wait until we are in a new generation */ while (1) { next_generation = get_generation(ctdb); if (next_generation != generation) { return 0; } sleep(1); } return 0; } /* display monitoring mode of a remote node */ static int control_getmonmode(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t monmode; int ret; ret = ctdb_ctrl_getmonmode(ctdb, TIMELIMIT(), options.pnn, &monmode); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get monmode from node %u\n", options.pnn)); return ret; } if (!options.machinereadable){ printf("Monitoring mode:%s (%d)\n",monmode==CTDB_MONITORING_ACTIVE?"ACTIVE":"DISABLED",monmode); } else { printf(":mode:\n"); printf(":%d:\n",monmode); } return 0; } /* display capabilities of a remote node */ static int control_getcapabilities(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t capabilities; int ret; ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), options.pnn, &capabilities); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", options.pnn)); return -1; } if (!options.machinereadable){ printf("RECMASTER: %s\n", (capabilities&CTDB_CAP_RECMASTER)?"YES":"NO"); printf("LMASTER: %s\n", (capabilities&CTDB_CAP_LMASTER)?"YES":"NO"); printf("LVS: %s\n", (capabilities&CTDB_CAP_LVS)?"YES":"NO"); printf("NATGW: %s\n", (capabilities&CTDB_CAP_NATGW)?"YES":"NO"); } else { printf(":RECMASTER:LMASTER:LVS:NATGW:\n"); printf(":%d:%d:%d:%d:\n", !!(capabilities&CTDB_CAP_RECMASTER), !!(capabilities&CTDB_CAP_LMASTER), !!(capabilities&CTDB_CAP_LVS), !!(capabilities&CTDB_CAP_NATGW)); } return 0; } /* display lvs configuration */ static int control_lvs(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); uint32_t *capabilities; struct ctdb_node_map *nodemap=NULL; int i, ret; int healthy_count = 0; ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } capabilities = talloc_array(ctdb, uint32_t, nodemap->num); CTDB_NO_MEMORY(ctdb, capabilities); ret = 0; /* collect capabilities for all connected nodes */ for (i=0; inum; i++) { if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { continue; } if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) { continue; } ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i)); ret = -1; goto done; } if (!(capabilities[i] & CTDB_CAP_LVS)) { continue; } if (!(nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY)) { healthy_count++; } } /* Print all LVS nodes */ for (i=0; inum; i++) { if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { continue; } if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) { continue; } if (!(capabilities[i] & CTDB_CAP_LVS)) { continue; } if (healthy_count != 0) { if (nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY) { continue; } } printf("%d:%s\n", i, ctdb_addr_to_str(&nodemap->nodes[i].addr)); } done: talloc_free(tmp_ctx); return ret; } /* display who is the lvs master */ static int control_lvsmaster(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); uint32_t *capabilities; struct ctdb_node_map *nodemap=NULL; int i, ret; int healthy_count = 0; ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return -1; } capabilities = talloc_array(tmp_ctx, uint32_t, nodemap->num); if (capabilities == NULL) { talloc_free(tmp_ctx); CTDB_NO_MEMORY(ctdb, capabilities); } /* collect capabilities for all connected nodes */ for (i=0; inum; i++) { if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { continue; } if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) { continue; } ret = ctdb_ctrl_getcapabilities(ctdb, TIMELIMIT(), i, &capabilities[i]); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get capabilities from node %u\n", i)); ret = -1; goto done; } if (!(capabilities[i] & CTDB_CAP_LVS)) { continue; } if (!(nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY)) { healthy_count++; } } ret = -1; /* find and show the lvsmaster */ for (i=0; inum; i++) { if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) { continue; } if (nodemap->nodes[i].flags & NODE_FLAGS_PERMANENTLY_DISABLED) { continue; } if (!(capabilities[i] & CTDB_CAP_LVS)) { continue; } if (healthy_count != 0) { if (nodemap->nodes[i].flags & NODE_FLAGS_UNHEALTHY) { continue; } } if (options.machinereadable){ printf("%d\n", i); } else { printf("Node %d is LVS master\n", i); } ret = 0; goto done; } printf("There is no LVS master\n"); done: talloc_free(tmp_ctx); return ret; } /* disable monitoring on a node */ static int control_disable_monmode(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; ret = ctdb_ctrl_disable_monmode(ctdb, TIMELIMIT(), options.pnn); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to disable monmode on node %u\n", options.pnn)); return ret; } printf("Monitoring mode:%s\n","DISABLED"); return 0; } /* enable monitoring on a node */ static int control_enable_monmode(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; ret = ctdb_ctrl_enable_monmode(ctdb, TIMELIMIT(), options.pnn); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to enable monmode on node %u\n", options.pnn)); return ret; } printf("Monitoring mode:%s\n","ACTIVE"); return 0; } /* display remote list of keys/data for a db */ static int control_catdb(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; int ret; struct ctdb_dump_db_context c; uint8_t flags; if (argc < 1) { usage(); } if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) { return -1; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); return -1; } if (options.printlmaster) { ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &ctdb->vnn_map); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n", options.pnn)); return ret; } } ZERO_STRUCT(c); c.f = stdout; c.printemptyrecords = (bool)options.printemptyrecords; c.printdatasize = (bool)options.printdatasize; c.printlmaster = (bool)options.printlmaster; c.printhash = (bool)options.printhash; c.printrecordflags = (bool)options.printrecordflags; /* traverse and dump the cluster tdb */ ret = ctdb_dump_db(ctdb_db, &c); if (ret == -1) { DEBUG(DEBUG_ERR, ("Unable to dump database\n")); DEBUG(DEBUG_ERR, ("Maybe try 'ctdb getdbstatus %s'" " and 'ctdb getvar AllowUnhealthyDBRead'\n", db_name)); return -1; } talloc_free(ctdb_db); printf("Dumped %d records\n", ret); return 0; } struct cattdb_data { struct ctdb_context *ctdb; uint32_t count; }; static int cattdb_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data) { struct cattdb_data *d = private_data; struct ctdb_dump_db_context c; d->count++; ZERO_STRUCT(c); c.f = stdout; c.printemptyrecords = (bool)options.printemptyrecords; c.printdatasize = (bool)options.printdatasize; c.printlmaster = false; c.printhash = (bool)options.printhash; c.printrecordflags = true; return ctdb_dumpdb_record(d->ctdb, key, data, &c); } /* cat the local tdb database using same format as catdb */ static int control_cattdb(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; struct cattdb_data d; uint8_t flags; if (argc < 1) { usage(); } if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) { return -1; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); return -1; } /* traverse the local tdb */ d.count = 0; d.ctdb = ctdb; if (tdb_traverse_read(ctdb_db->ltdb->tdb, cattdb_traverse, &d) == -1) { printf("Failed to cattdb data\n"); exit(10); } talloc_free(ctdb_db); printf("Dumped %d records\n", d.count); return 0; } /* display the content of a database key */ static int control_readkey(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; struct ctdb_record_handle *h; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); TDB_DATA key, data; uint8_t flags; if (argc < 2) { usage(); } if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) { return -1; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); return -1; } key.dptr = discard_const(argv[1]); key.dsize = strlen((char *)key.dptr); h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data); if (h == NULL) { printf("Failed to fetch record '%s' on node %d\n", (const char *)key.dptr, ctdb_get_pnn(ctdb)); talloc_free(tmp_ctx); exit(10); } printf("Data: size:%d ptr:[%.*s]\n", (int)data.dsize, (int)data.dsize, data.dptr); talloc_free(ctdb_db); talloc_free(tmp_ctx); return 0; } /* display the content of a database key */ static int control_writekey(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; struct ctdb_record_handle *h; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); TDB_DATA key, data; uint8_t flags; if (argc < 3) { usage(); } if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) { return -1; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); return -1; } key.dptr = discard_const(argv[1]); key.dsize = strlen((char *)key.dptr); h = ctdb_fetch_lock(ctdb_db, tmp_ctx, key, &data); if (h == NULL) { printf("Failed to fetch record '%s' on node %d\n", (const char *)key.dptr, ctdb_get_pnn(ctdb)); talloc_free(tmp_ctx); exit(10); } data.dptr = discard_const(argv[2]); data.dsize = strlen((char *)data.dptr); if (ctdb_record_store(h, data) != 0) { printf("Failed to store record\n"); } talloc_free(h); talloc_free(ctdb_db); talloc_free(tmp_ctx); return 0; } /* fetch a record from a persistent database */ static int control_pfetch(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_transaction_handle *h; TDB_DATA key, data; int fd, ret; bool persistent; uint8_t flags; if (argc < 2) { talloc_free(tmp_ctx); usage(); } if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) { talloc_free(tmp_ctx); return -1; } persistent = flags & CTDB_DB_FLAGS_PERSISTENT; if (!persistent) { DEBUG(DEBUG_ERR,("Database '%s' is not persistent\n", db_name)); talloc_free(tmp_ctx); return -1; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); talloc_free(tmp_ctx); return -1; } h = ctdb_transaction_start(ctdb_db, tmp_ctx); if (h == NULL) { DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", db_name)); talloc_free(tmp_ctx); return -1; } key.dptr = discard_const(argv[1]); key.dsize = strlen(argv[1]); ret = ctdb_transaction_fetch(h, tmp_ctx, key, &data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to fetch record\n")); talloc_free(tmp_ctx); return -1; } if (data.dsize == 0 || data.dptr == NULL) { DEBUG(DEBUG_ERR,("Record is empty\n")); talloc_free(tmp_ctx); return -1; } if (argc == 3) { fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600); if (fd == -1) { DEBUG(DEBUG_ERR,("Failed to open output file %s\n", argv[2])); talloc_free(tmp_ctx); return -1; } write(fd, data.dptr, data.dsize); close(fd); } else { write(1, data.dptr, data.dsize); } /* abort the transaction */ talloc_free(h); talloc_free(tmp_ctx); return 0; } /* fetch a record from a tdb-file */ static int control_tfetch(struct ctdb_context *ctdb, int argc, const char **argv) { const char *tdb_file; TDB_CONTEXT *tdb; TDB_DATA key, data; TALLOC_CTX *tmp_ctx = talloc_new(NULL); int fd; if (argc < 2) { usage(); } tdb_file = argv[0]; tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0); if (tdb == NULL) { printf("Failed to open TDB file %s\n", tdb_file); return -1; } if (!strncmp(argv[1], "0x", 2)) { key = hextodata(tmp_ctx, argv[1] + 2); if (key.dsize == 0) { printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]); return -1; } } else { key.dptr = discard_const(argv[1]); key.dsize = strlen(argv[1]); } data = tdb_fetch(tdb, key); if (data.dptr == NULL || data.dsize < sizeof(struct ctdb_ltdb_header)) { printf("Failed to read record %s from tdb %s\n", argv[1], tdb_file); tdb_close(tdb); return -1; } tdb_close(tdb); if (argc == 3) { fd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600); if (fd == -1) { printf("Failed to open output file %s\n", argv[2]); return -1; } if (options.verbose){ write(fd, data.dptr, data.dsize); } else { write(fd, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header)); } close(fd); } else { if (options.verbose){ write(1, data.dptr, data.dsize); } else { write(1, data.dptr+sizeof(struct ctdb_ltdb_header), data.dsize-sizeof(struct ctdb_ltdb_header)); } } talloc_free(tmp_ctx); return 0; } /* store a record and header to a tdb-file */ static int control_tstore(struct ctdb_context *ctdb, int argc, const char **argv) { const char *tdb_file; TDB_CONTEXT *tdb; TDB_DATA key, value, data; TALLOC_CTX *tmp_ctx = talloc_new(NULL); struct ctdb_ltdb_header header; if (argc < 3) { usage(); } tdb_file = argv[0]; tdb = tdb_open(tdb_file, 0, 0, O_RDWR, 0); if (tdb == NULL) { printf("Failed to open TDB file %s\n", tdb_file); return -1; } if (!strncmp(argv[1], "0x", 2)) { key = hextodata(tmp_ctx, argv[1] + 2); if (key.dsize == 0) { printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[1]); return -1; } } else { key.dptr = discard_const(argv[1]); key.dsize = strlen(argv[1]); } if (!strncmp(argv[2], "0x", 2)) { value = hextodata(tmp_ctx, argv[2] + 2); if (value.dsize == 0) { printf("Failed to convert \"%s\" into a TDB_DATA\n", argv[2]); return -1; } } else { value.dptr = discard_const(argv[2]); value.dsize = strlen(argv[2]); } ZERO_STRUCT(header); if (argc > 3) { header.rsn = atoll(argv[3]); } if (argc > 4) { header.dmaster = atoi(argv[4]); } if (argc > 5) { header.flags = atoi(argv[5]); } data.dsize = sizeof(struct ctdb_ltdb_header) + value.dsize; data.dptr = talloc_size(tmp_ctx, data.dsize); if (data.dptr == NULL) { printf("Failed to allocate header+value\n"); return -1; } *(struct ctdb_ltdb_header *)data.dptr = header; memcpy(data.dptr + sizeof(struct ctdb_ltdb_header), value.dptr, value.dsize); if (tdb_store(tdb, key, data, TDB_REPLACE) != 0) { printf("Failed to write record %s to tdb %s\n", argv[1], tdb_file); tdb_close(tdb); return -1; } tdb_close(tdb); talloc_free(tmp_ctx); return 0; } /* write a record to a persistent database */ static int control_pstore(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_transaction_handle *h; struct stat st; TDB_DATA key, data; int fd, ret; if (argc < 3) { talloc_free(tmp_ctx); usage(); } fd = open(argv[2], O_RDONLY); if (fd == -1) { DEBUG(DEBUG_ERR,("Failed to open file containing record data : %s %s\n", argv[2], strerror(errno))); talloc_free(tmp_ctx); return -1; } ret = fstat(fd, &st); if (ret == -1) { DEBUG(DEBUG_ERR,("fstat of file %s failed: %s\n", argv[2], strerror(errno))); close(fd); talloc_free(tmp_ctx); return -1; } if (!S_ISREG(st.st_mode)) { DEBUG(DEBUG_ERR,("Not a regular file %s\n", argv[2])); close(fd); talloc_free(tmp_ctx); return -1; } data.dsize = st.st_size; if (data.dsize == 0) { data.dptr = NULL; } else { data.dptr = talloc_size(tmp_ctx, data.dsize); if (data.dptr == NULL) { DEBUG(DEBUG_ERR,("Failed to talloc %d of memory to store record data\n", (int)data.dsize)); close(fd); talloc_free(tmp_ctx); return -1; } ret = read(fd, data.dptr, data.dsize); if (ret != data.dsize) { DEBUG(DEBUG_ERR,("Failed to read %d bytes of record data\n", (int)data.dsize)); close(fd); talloc_free(tmp_ctx); return -1; } } close(fd); db_name = argv[0]; ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, true, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); talloc_free(tmp_ctx); return -1; } h = ctdb_transaction_start(ctdb_db, tmp_ctx); if (h == NULL) { DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", db_name)); talloc_free(tmp_ctx); return -1; } key.dptr = discard_const(argv[1]); key.dsize = strlen(argv[1]); ret = ctdb_transaction_store(h, key, data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to store record\n")); talloc_free(tmp_ctx); return -1; } ret = ctdb_transaction_commit(h); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to commit transaction\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } /* * delete a record from a persistent database */ static int control_pdelete(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_transaction_handle *h; TDB_DATA key; int ret; bool persistent; uint8_t flags; if (argc < 2) { talloc_free(tmp_ctx); usage(); } if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) { talloc_free(tmp_ctx); return -1; } persistent = flags & CTDB_DB_FLAGS_PERSISTENT; if (!persistent) { DEBUG(DEBUG_ERR, ("Database '%s' is not persistent\n", db_name)); talloc_free(tmp_ctx); return -1; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR, ("Unable to attach to database '%s'\n", db_name)); talloc_free(tmp_ctx); return -1; } h = ctdb_transaction_start(ctdb_db, tmp_ctx); if (h == NULL) { DEBUG(DEBUG_ERR, ("Failed to start transaction on database %s\n", db_name)); talloc_free(tmp_ctx); return -1; } key.dptr = discard_const(argv[1]); key.dsize = strlen(argv[1]); ret = ctdb_transaction_store(h, key, tdb_null); if (ret != 0) { DEBUG(DEBUG_ERR, ("Failed to delete record\n")); talloc_free(tmp_ctx); return -1; } ret = ctdb_transaction_commit(h); if (ret != 0) { DEBUG(DEBUG_ERR, ("Failed to commit transaction\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } static const char *ptrans_parse_string(TALLOC_CTX *mem_ctx, const char *s, TDB_DATA *data) { const char *t; size_t n; const char *ret; /* Next byte after successfully parsed value */ /* Error, unless someone says otherwise */ ret = NULL; /* Indicates no value to parse */ *data = tdb_null; /* Skip whitespace */ n = strspn(s, " \t"); t = s + n; if (t[0] == '"') { /* Quoted ASCII string - no wide characters! */ t++; n = strcspn(t, "\""); if (t[n] == '"') { if (n > 0) { data->dsize = n; data->dptr = talloc_memdup(mem_ctx, t, n); CTDB_NOMEM_ABORT(data->dptr); } ret = t + n + 1; } else { DEBUG(DEBUG_WARNING,("Unmatched \" in input %s\n", s)); } } else { DEBUG(DEBUG_WARNING,("Unsupported input format in %s\n", s)); } return ret; } static bool ptrans_get_key_value(TALLOC_CTX *mem_ctx, FILE *file, TDB_DATA *key, TDB_DATA *value) { char line [1024]; /* FIXME: make this more flexible? */ const char *t; char *ptr; ptr = fgets(line, sizeof(line), file); if (ptr == NULL) { return false; } /* Get key */ t = ptrans_parse_string(mem_ctx, line, key); if (t == NULL || key->dptr == NULL) { /* Line Ignored but not EOF */ return true; } /* Get value */ t = ptrans_parse_string(mem_ctx, t, value); if (t == NULL) { /* Line Ignored but not EOF */ talloc_free(key->dptr); *key = tdb_null; return true; } return true; } /* * Update a persistent database as per file/stdin */ static int control_ptrans(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; struct ctdb_db_context *ctdb_db; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct ctdb_transaction_handle *h; TDB_DATA key, value; FILE *file; int ret; if (argc < 1) { talloc_free(tmp_ctx); usage(); } file = stdin; if (argc == 2) { file = fopen(argv[1], "r"); if (file == NULL) { DEBUG(DEBUG_ERR,("Unable to open file for reading '%s'\n", argv[1])); talloc_free(tmp_ctx); return -1; } } db_name = argv[0]; ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, true, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); goto error; } h = ctdb_transaction_start(ctdb_db, tmp_ctx); if (h == NULL) { DEBUG(DEBUG_ERR,("Failed to start transaction on database %s\n", db_name)); goto error; } while (ptrans_get_key_value(tmp_ctx, file, &key, &value)) { if (key.dsize != 0) { ret = ctdb_transaction_store(h, key, value); /* Minimise memory use */ talloc_free(key.dptr); if (value.dptr != NULL) { talloc_free(value.dptr); } if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to store record\n")); ctdb_transaction_cancel(h); goto error; } } } ret = ctdb_transaction_commit(h); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to commit transaction\n")); goto error; } if (file != stdin) { fclose(file); } talloc_free(tmp_ctx); return 0; error: if (file != stdin) { fclose(file); } talloc_free(tmp_ctx); return -1; } /* check if a service is bound to a port or not */ static int control_chktcpport(struct ctdb_context *ctdb, int argc, const char **argv) { int s, ret; int v; int port; struct sockaddr_in sin; if (argc != 1) { printf("Use: ctdb chktcport \n"); return EINVAL; } port = atoi(argv[0]); s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == -1) { printf("Failed to open local socket\n"); return errno; } v = fcntl(s, F_GETFL, 0); if (v == -1 || fcntl(s, F_SETFL, v | O_NONBLOCK) != 0) { printf("Unable to set socket non-blocking: %s\n", strerror(errno)); } bzero(&sin, sizeof(sin)); sin.sin_family = PF_INET; sin.sin_port = htons(port); ret = bind(s, (struct sockaddr *)&sin, sizeof(sin)); close(s); if (ret == -1) { printf("Failed to bind to local socket: %d %s\n", errno, strerror(errno)); return errno; } return 0; } static void log_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *private_data) { DEBUG(DEBUG_ERR,("Log data received\n")); if (data.dsize > 0) { printf("%s", data.dptr); } exit(0); } /* display a list of log messages from the in memory ringbuffer */ static int control_getlog(struct ctdb_context *ctdb, int argc, const char **argv) { int ret, i; bool main_daemon; struct ctdb_get_log_addr log_addr; TDB_DATA data; struct timeval tv; /* Process options */ main_daemon = true; log_addr.pnn = ctdb_get_pnn(ctdb); log_addr.level = DEBUG_NOTICE; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "recoverd") == 0) { main_daemon = false; } else { if (isalpha(argv[i][0]) || argv[i][0] == '-') { log_addr.level = get_debug_by_desc(argv[i]); } else { log_addr.level = strtol(argv[i], NULL, 0); } } } /* Our message port is our PID */ log_addr.srvid = getpid(); data.dptr = (unsigned char *)&log_addr; data.dsize = sizeof(log_addr); DEBUG(DEBUG_ERR, ("Pulling logs from node %u\n", options.pnn)); ctdb_client_set_message_handler(ctdb, log_addr.srvid, log_handler, NULL); sleep(1); DEBUG(DEBUG_ERR,("Listen for response on %d\n", (int)log_addr.srvid)); if (main_daemon) { int32_t res; char *errmsg; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_GET_LOG, 0, data, tmp_ctx, NULL, &res, NULL, &errmsg); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("Failed to get logs - %s\n", errmsg)); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); } else { ret = ctdb_client_send_message(ctdb, options.pnn, CTDB_SRVID_GETLOG, data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to send getlog request message to %u\n", options.pnn)); return -1; } } tv = timeval_current(); /* this loop will terminate when we have received the reply */ while (timeval_elapsed(&tv) < (double)options.timelimit) { event_loop_once(ctdb->ev); } DEBUG(DEBUG_INFO,("Timed out waiting for log data.\n")); return 0; } /* clear the in memory log area */ static int control_clearlog(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; if (argc == 0 || (argc >= 1 && strcmp(argv[0], "recoverd") != 0)) { /* "recoverd" not given - get logs from main daemon */ int32_t res; char *errmsg; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_CLEAR_LOG, 0, tdb_null, tmp_ctx, NULL, &res, NULL, &errmsg); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("Failed to clear logs\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); } else { TDB_DATA data; /* unused in recoverd... */ data.dsize = 0; ret = ctdb_client_send_message(ctdb, options.pnn, CTDB_SRVID_CLEARLOG, data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to send clearlog request message to %u\n", options.pnn)); return -1; } } return 0; } /* Reload public IPs on a specified nodes */ static int control_reloadips(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); uint32_t *nodes; uint32_t pnn_mode; uint32_t timeout; int ret; assert_single_node_only(); if (argc > 1) { usage(); } /* Determine the nodes where IPs need to be reloaded */ if (!parse_nodestring(ctdb, tmp_ctx, argc == 1 ? argv[0] : NULL, options.pnn, true, &nodes, &pnn_mode)) { ret = -1; goto done; } again: /* Disable takeover runs on all connected nodes. A reply * indicating success is needed from each node so all nodes * will need to be active. This will retry until maxruntime * is exceeded, hence no error handling. * * A check could be added to not allow reloading of IPs when * there are disconnected nodes. However, this should * probably be left up to the administrator. */ timeout = LONGTIMEOUT; srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_TAKEOVER_RUNS, &timeout, "Disable takeover runs", true); /* Now tell all the desired nodes to reload their public IPs. * Keep trying this until it succeeds. This assumes all * failures are transient, which might not be true... */ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_RELOAD_PUBLIC_IPS, nodes, 0, LONGTIMELIMIT(), false, tdb_null, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to reload IPs on some nodes, try again.\n")); goto again; } /* It isn't strictly necessary to wait until takeover runs are * re-enabled but doing so can't hurt. */ timeout = 0; srvid_broadcast(ctdb, CTDB_SRVID_DISABLE_TAKEOVER_RUNS, &timeout, "Enable takeover runs", true); ipreallocate(ctdb); ret = 0; done: talloc_free(tmp_ctx); return ret; } /* display a list of the databases on a remote ctdb */ static int control_getdbmap(struct ctdb_context *ctdb, int argc, const char **argv) { int i, ret; struct ctdb_dbid_map *dbmap=NULL; ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, ctdb, &dbmap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn)); return ret; } if(options.machinereadable){ printf(":ID:Name:Path:Persistent:Sticky:Unhealthy:ReadOnly:\n"); for(i=0;inum;i++){ const char *path; const char *name; const char *health; bool persistent; bool readonly; bool sticky; ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &path); ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name); ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &health); persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT; readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY; sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY; printf(":0x%08X:%s:%s:%d:%d:%d:%d:\n", dbmap->dbs[i].dbid, name, path, !!(persistent), !!(sticky), !!(health), !!(readonly)); } return 0; } printf("Number of databases:%d\n", dbmap->num); for(i=0;inum;i++){ const char *path; const char *name; const char *health; bool persistent; bool readonly; bool sticky; ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &path); ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &name); ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, ctdb, &health); persistent = dbmap->dbs[i].flags & CTDB_DB_FLAGS_PERSISTENT; readonly = dbmap->dbs[i].flags & CTDB_DB_FLAGS_READONLY; sticky = dbmap->dbs[i].flags & CTDB_DB_FLAGS_STICKY; printf("dbid:0x%08x name:%s path:%s%s%s%s%s\n", dbmap->dbs[i].dbid, name, path, persistent?" PERSISTENT":"", sticky?" STICKY":"", readonly?" READONLY":"", health?" UNHEALTHY":""); } return 0; } /* display the status of a database on a remote ctdb */ static int control_getdbstatus(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; uint32_t db_id; uint8_t flags; const char *path; const char *health; if (argc < 1) { usage(); } if (!db_exists(ctdb, argv[0], &db_id, &db_name, &flags)) { return -1; } ctdb_ctrl_getdbpath(ctdb, TIMELIMIT(), options.pnn, db_id, ctdb, &path); ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, db_id, ctdb, &health); printf("dbid: 0x%08x\nname: %s\npath: %s\nPERSISTENT: %s\nSTICKY: %s\nREADONLY: %s\nHEALTH: %s\n", db_id, db_name, path, (flags & CTDB_DB_FLAGS_PERSISTENT ? "yes" : "no"), (flags & CTDB_DB_FLAGS_STICKY ? "yes" : "no"), (flags & CTDB_DB_FLAGS_READONLY ? "yes" : "no"), (health ? health : "OK")); return 0; } /* check if the local node is recmaster or not it will return 1 if this node is the recmaster and 0 if it is not or if the local ctdb daemon could not be contacted */ static int control_isnotrecmaster(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t mypnn, recmaster; int ret; assert_single_node_only(); mypnn = getpnn(ctdb); ret = ctdb_ctrl_getrecmaster(ctdb, ctdb, TIMELIMIT(), options.pnn, &recmaster); if (ret != 0) { printf("Failed to get the recmaster\n"); return 1; } if (recmaster != mypnn) { printf("this node is not the recmaster\n"); return 1; } printf("this node is the recmaster\n"); return 0; } /* ping a node */ static int control_ping(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; struct timeval tv = timeval_current(); ret = ctdb_ctrl_ping(ctdb, options.pnn); if (ret == -1) { printf("Unable to get ping response from node %u\n", options.pnn); return -1; } else { printf("response from %u time=%.6f sec (%d clients)\n", options.pnn, timeval_elapsed(&tv), ret); } return 0; } /* get a node's runstate */ static int control_runstate(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; enum ctdb_runstate runstate; ret = ctdb_ctrl_get_runstate(ctdb, TIMELIMIT(), options.pnn, &runstate); if (ret == -1) { printf("Unable to get runstate response from node %u\n", options.pnn); return -1; } else { bool found = true; enum ctdb_runstate t; int i; for (i=0; i 2) { usage(); } if (argc == 2) { if (strcmp(argv[1], "persistent") != 0) { usage(); } persistent = true; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, persistent, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", db_name)); return -1; } return 0; } /* set db priority */ static int control_setdbprio(struct ctdb_context *ctdb, int argc, const char **argv) { struct ctdb_db_priority db_prio; int ret; if (argc < 2) { usage(); } db_prio.db_id = strtoul(argv[0], NULL, 0); db_prio.priority = strtoul(argv[1], NULL, 0); ret = ctdb_ctrl_set_db_priority(ctdb, TIMELIMIT(), options.pnn, &db_prio); if (ret != 0) { DEBUG(DEBUG_ERR,("Unable to set db prio\n")); return -1; } return 0; } /* get db priority */ static int control_getdbprio(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t db_id, priority; int ret; if (argc < 1) { usage(); } if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) { return -1; } ret = ctdb_ctrl_get_db_priority(ctdb, TIMELIMIT(), options.pnn, db_id, &priority); if (ret != 0) { DEBUG(DEBUG_ERR,("Unable to get db prio\n")); return -1; } DEBUG(DEBUG_ERR,("Priority:%u\n", priority)); return 0; } /* set the sticky records capability for a database */ static int control_setdbsticky(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); uint32_t db_id; int ret; if (argc < 1) { usage(); } if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) { return -1; } ret = ctdb_ctrl_set_db_sticky(ctdb, options.pnn, db_id); if (ret != 0) { DEBUG(DEBUG_ERR,("Unable to set db to support sticky records\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } /* set the readonly capability for a database */ static int control_setdbreadonly(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); uint32_t db_id; int ret; if (argc < 1) { usage(); } if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) { return -1; } ret = ctdb_ctrl_set_db_readonly(ctdb, options.pnn, db_id); if (ret != 0) { DEBUG(DEBUG_ERR,("Unable to set db to support readonly\n")); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } /* get db seqnum */ static int control_getdbseqnum(struct ctdb_context *ctdb, int argc, const char **argv) { uint32_t db_id; uint64_t seqnum; int ret; if (argc < 1) { usage(); } if (!db_exists(ctdb, argv[0], &db_id, NULL, NULL)) { return -1; } ret = ctdb_ctrl_getdbseqnum(ctdb, TIMELIMIT(), options.pnn, db_id, &seqnum); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get seqnum from node.")); return -1; } printf("Sequence number:%lld\n", (long long)seqnum); return 0; } /* run an eventscript on a node */ static int control_eventscript(struct ctdb_context *ctdb, int argc, const char **argv) { TDB_DATA data; int ret; int32_t res; char *errmsg; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); if (argc != 1) { DEBUG(DEBUG_ERR,("Invalid arguments\n")); return -1; } data.dptr = (unsigned char *)discard_const(argv[0]); data.dsize = strlen((char *)data.dptr) + 1; DEBUG(DEBUG_ERR, ("Running eventscripts with arguments \"%s\" on node %u\n", data.dptr, options.pnn)); ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_RUN_EVENTSCRIPTS, 0, data, tmp_ctx, NULL, &res, NULL, &errmsg); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("Failed to run eventscripts - %s\n", errmsg)); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } #define DB_VERSION 1 #define MAX_DB_NAME 64 struct db_file_header { unsigned long version; time_t timestamp; unsigned long persistent; unsigned long size; const char name[MAX_DB_NAME]; }; struct backup_data { struct ctdb_marshall_buffer *records; uint32_t len; uint32_t total; bool traverse_error; }; static int backup_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private) { struct backup_data *bd = talloc_get_type(private, struct backup_data); struct ctdb_rec_data *rec; /* add the record */ rec = ctdb_marshall_record(bd->records, 0, key, NULL, data); if (rec == NULL) { bd->traverse_error = true; DEBUG(DEBUG_ERR,("Failed to marshall record\n")); return -1; } bd->records = talloc_realloc_size(NULL, bd->records, rec->length + bd->len); if (bd->records == NULL) { DEBUG(DEBUG_ERR,("Failed to expand marshalling buffer\n")); bd->traverse_error = true; return -1; } bd->records->count++; memcpy(bd->len+(uint8_t *)bd->records, rec, rec->length); bd->len += rec->length; talloc_free(rec); bd->total++; return 0; } /* * backup a database to a file */ static int control_backupdb(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; int ret; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); struct db_file_header dbhdr; struct ctdb_db_context *ctdb_db; struct backup_data *bd; int fh = -1; int status = -1; const char *reason = NULL; uint32_t db_id; uint8_t flags; assert_single_node_only(); if (argc != 2) { DEBUG(DEBUG_ERR,("Invalid arguments\n")); return -1; } if (!db_exists(ctdb, argv[0], &db_id, &db_name, &flags)) { return -1; } ret = ctdb_ctrl_getdbhealth(ctdb, TIMELIMIT(), options.pnn, db_id, tmp_ctx, &reason); if (ret != 0) { DEBUG(DEBUG_ERR,("Unable to get dbhealth for database '%s'\n", argv[0])); talloc_free(tmp_ctx); return -1; } if (reason) { uint32_t allow_unhealthy = 0; ctdb_ctrl_get_tunable(ctdb, TIMELIMIT(), options.pnn, "AllowUnhealthyDBRead", &allow_unhealthy); if (allow_unhealthy != 1) { DEBUG(DEBUG_ERR,("database '%s' is unhealthy: %s\n", argv[0], reason)); DEBUG(DEBUG_ERR,("disallow backup : tunable AllowUnhealthyDBRead = %u\n", allow_unhealthy)); talloc_free(tmp_ctx); return -1; } DEBUG(DEBUG_WARNING,("WARNING database '%s' is unhealthy - see 'ctdb getdbstatus %s'\n", argv[0], argv[0])); DEBUG(DEBUG_WARNING,("WARNING! allow backup of unhealthy database: " "tunnable AllowUnhealthyDBRead = %u\n", allow_unhealthy)); } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", argv[0])); talloc_free(tmp_ctx); return -1; } ret = tdb_transaction_start(ctdb_db->ltdb->tdb); if (ret == -1) { DEBUG(DEBUG_ERR,("Failed to start transaction\n")); talloc_free(tmp_ctx); return -1; } bd = talloc_zero(tmp_ctx, struct backup_data); if (bd == NULL) { DEBUG(DEBUG_ERR,("Failed to allocate backup_data\n")); talloc_free(tmp_ctx); return -1; } bd->records = talloc_zero(bd, struct ctdb_marshall_buffer); if (bd->records == NULL) { DEBUG(DEBUG_ERR,("Failed to allocate ctdb_marshall_buffer\n")); talloc_free(tmp_ctx); return -1; } bd->len = offsetof(struct ctdb_marshall_buffer, data); bd->records->db_id = ctdb_db->db_id; /* traverse the database collecting all records */ if (tdb_traverse_read(ctdb_db->ltdb->tdb, backup_traverse, bd) == -1 || bd->traverse_error) { DEBUG(DEBUG_ERR,("Traverse error\n")); talloc_free(tmp_ctx); return -1; } tdb_transaction_cancel(ctdb_db->ltdb->tdb); fh = open(argv[1], O_RDWR|O_CREAT, 0600); if (fh == -1) { DEBUG(DEBUG_ERR,("Failed to open file '%s'\n", argv[1])); talloc_free(tmp_ctx); return -1; } ZERO_STRUCT(dbhdr); dbhdr.version = DB_VERSION; dbhdr.timestamp = time(NULL); dbhdr.persistent = flags & CTDB_DB_FLAGS_PERSISTENT; dbhdr.size = bd->len; if (strlen(argv[0]) >= MAX_DB_NAME) { DEBUG(DEBUG_ERR,("Too long dbname\n")); goto done; } strncpy(discard_const(dbhdr.name), argv[0], MAX_DB_NAME-1); ret = write(fh, &dbhdr, sizeof(dbhdr)); if (ret == -1) { DEBUG(DEBUG_ERR,("write failed: %s\n", strerror(errno))); goto done; } ret = write(fh, bd->records, bd->len); if (ret == -1) { DEBUG(DEBUG_ERR,("write failed: %s\n", strerror(errno))); goto done; } status = 0; done: if (fh != -1) { ret = close(fh); if (ret == -1) { DEBUG(DEBUG_ERR,("close failed: %s\n", strerror(errno))); } } DEBUG(DEBUG_ERR,("Database backed up to %s\n", argv[1])); talloc_free(tmp_ctx); return status; } /* * restore a database from a file */ static int control_restoredb(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); TDB_DATA outdata; TDB_DATA data; struct db_file_header dbhdr; struct ctdb_db_context *ctdb_db; struct ctdb_node_map *nodemap=NULL; struct ctdb_vnn_map *vnnmap=NULL; int i, fh; struct ctdb_control_wipe_database w; uint32_t *nodes; uint32_t generation; struct tm *tm; char tbuf[100]; char *dbname; assert_single_node_only(); if (argc < 1 || argc > 2) { DEBUG(DEBUG_ERR,("Invalid arguments\n")); return -1; } fh = open(argv[0], O_RDONLY); if (fh == -1) { DEBUG(DEBUG_ERR,("Failed to open file '%s'\n", argv[0])); talloc_free(tmp_ctx); return -1; } read(fh, &dbhdr, sizeof(dbhdr)); if (dbhdr.version != DB_VERSION) { DEBUG(DEBUG_ERR,("Invalid version of database dump. File is version %lu but expected version was %u\n", dbhdr.version, DB_VERSION)); close(fh); talloc_free(tmp_ctx); return -1; } dbname = discard_const(dbhdr.name); if (argc == 2) { dbname = discard_const(argv[1]); } outdata.dsize = dbhdr.size; outdata.dptr = talloc_size(tmp_ctx, outdata.dsize); if (outdata.dptr == NULL) { DEBUG(DEBUG_ERR,("Failed to allocate data of size '%lu'\n", dbhdr.size)); close(fh); talloc_free(tmp_ctx); return -1; } read(fh, outdata.dptr, outdata.dsize); close(fh); tm = localtime(&dbhdr.timestamp); strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm); printf("Restoring database '%s' from backup @ %s\n", dbname, tbuf); ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), dbname, dbhdr.persistent, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unable to attach to database '%s'\n", dbname)); talloc_free(tmp_ctx); return -1; } ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &vnnmap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } /* freeze all nodes */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); for (i=1; i<=NUM_DB_PRIORITIES; i++) { if (ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE, nodes, i, TIMELIMIT(), false, tdb_null, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to freeze nodes.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } } generation = vnnmap->generation; data.dptr = (void *)&generation; data.dsize = sizeof(generation); /* start a cluster wide transaction */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_START, nodes, 0, TIMELIMIT(), false, data, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to start cluster wide transactions.\n")); return -1; } w.db_id = ctdb_db->db_id; w.transaction_id = generation; data.dptr = (void *)&w; data.dsize = sizeof(w); /* wipe all the remote databases. */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_WIPE_DATABASE, nodes, 0, TIMELIMIT(), false, data, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to wipe database.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } /* push the database */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_PUSH_DB, nodes, 0, TIMELIMIT(), false, outdata, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Failed to push database.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } data.dptr = (void *)&ctdb_db->db_id; data.dsize = sizeof(ctdb_db->db_id); /* mark the database as healthy */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_DB_SET_HEALTHY, nodes, 0, TIMELIMIT(), false, data, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Failed to mark database as healthy.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } data.dptr = (void *)&generation; data.dsize = sizeof(generation); /* commit all the changes */ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_COMMIT, nodes, 0, TIMELIMIT(), false, data, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to commit databases.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } /* thaw all nodes */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_THAW, nodes, 0, TIMELIMIT(), false, tdb_null, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to thaw nodes.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } talloc_free(tmp_ctx); return 0; } /* * dump a database backup from a file */ static int control_dumpdbbackup(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *tmp_ctx = talloc_new(ctdb); TDB_DATA outdata; struct db_file_header dbhdr; int i, fh; struct tm *tm; char tbuf[100]; struct ctdb_rec_data *rec = NULL; struct ctdb_marshall_buffer *m; struct ctdb_dump_db_context c; assert_single_node_only(); if (argc != 1) { DEBUG(DEBUG_ERR,("Invalid arguments\n")); return -1; } fh = open(argv[0], O_RDONLY); if (fh == -1) { DEBUG(DEBUG_ERR,("Failed to open file '%s'\n", argv[0])); talloc_free(tmp_ctx); return -1; } read(fh, &dbhdr, sizeof(dbhdr)); if (dbhdr.version != DB_VERSION) { DEBUG(DEBUG_ERR,("Invalid version of database dump. File is version %lu but expected version was %u\n", dbhdr.version, DB_VERSION)); close(fh); talloc_free(tmp_ctx); return -1; } outdata.dsize = dbhdr.size; outdata.dptr = talloc_size(tmp_ctx, outdata.dsize); if (outdata.dptr == NULL) { DEBUG(DEBUG_ERR,("Failed to allocate data of size '%lu'\n", dbhdr.size)); close(fh); talloc_free(tmp_ctx); return -1; } read(fh, outdata.dptr, outdata.dsize); close(fh); m = (struct ctdb_marshall_buffer *)outdata.dptr; tm = localtime(&dbhdr.timestamp); strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm); printf("Backup of database name:'%s' dbid:0x%x08x from @ %s\n", dbhdr.name, m->db_id, tbuf); ZERO_STRUCT(c); c.f = stdout; c.printemptyrecords = (bool)options.printemptyrecords; c.printdatasize = (bool)options.printdatasize; c.printlmaster = false; c.printhash = (bool)options.printhash; c.printrecordflags = (bool)options.printrecordflags; for (i=0; i < m->count; i++) { uint32_t reqid = 0; TDB_DATA key, data; /* we do not want the header splitted, so we pass NULL*/ rec = ctdb_marshall_loop_next(m, rec, &reqid, NULL, &key, &data); ctdb_dumpdb_record(ctdb, key, data, &c); } printf("Dumped %d records\n", i); talloc_free(tmp_ctx); return 0; } /* * wipe a database from a file */ static int control_wipedb(struct ctdb_context *ctdb, int argc, const char **argv) { const char *db_name; int ret; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); TDB_DATA data; struct ctdb_db_context *ctdb_db; struct ctdb_node_map *nodemap = NULL; struct ctdb_vnn_map *vnnmap = NULL; int i; struct ctdb_control_wipe_database w; uint32_t *nodes; uint32_t generation; uint8_t flags; assert_single_node_only(); if (argc != 1) { DEBUG(DEBUG_ERR,("Invalid arguments\n")); return -1; } if (!db_exists(ctdb, argv[0], NULL, &db_name, &flags)) { return -1; } ctdb_db = ctdb_attach(ctdb, TIMELIMIT(), db_name, flags & CTDB_DB_FLAGS_PERSISTENT, 0); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR, ("Unable to attach to database '%s'\n", argv[0])); talloc_free(tmp_ctx); return -1; } ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), options.pnn, ctdb, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } ret = ctdb_ctrl_getvnnmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &vnnmap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get vnnmap from node %u\n", options.pnn)); talloc_free(tmp_ctx); return ret; } /* freeze all nodes */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); for (i=1; i<=NUM_DB_PRIORITIES; i++) { ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_FREEZE, nodes, i, TIMELIMIT(), false, tdb_null, NULL, NULL, NULL); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to freeze nodes.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } } generation = vnnmap->generation; data.dptr = (void *)&generation; data.dsize = sizeof(generation); /* start a cluster wide transaction */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); ret = ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_START, nodes, 0, TIMELIMIT(), false, data, NULL, NULL, NULL); if (ret!= 0) { DEBUG(DEBUG_ERR, ("Unable to start cluster wide " "transactions.\n")); return -1; } w.db_id = ctdb_db->db_id; w.transaction_id = generation; data.dptr = (void *)&w; data.dsize = sizeof(w); /* wipe all the remote databases. */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_WIPE_DATABASE, nodes, 0, TIMELIMIT(), false, data, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to wipe database.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } data.dptr = (void *)&ctdb_db->db_id; data.dsize = sizeof(ctdb_db->db_id); /* mark the database as healthy */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_DB_SET_HEALTHY, nodes, 0, TIMELIMIT(), false, data, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Failed to mark database as healthy.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } data.dptr = (void *)&generation; data.dsize = sizeof(generation); /* commit all the changes */ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_TRANSACTION_COMMIT, nodes, 0, TIMELIMIT(), false, data, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to commit databases.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } /* thaw all nodes */ nodes = list_of_active_nodes(ctdb, nodemap, tmp_ctx, true); if (ctdb_client_async_control(ctdb, CTDB_CONTROL_THAW, nodes, 0, TIMELIMIT(), false, tdb_null, NULL, NULL, NULL) != 0) { DEBUG(DEBUG_ERR, ("Unable to thaw nodes.\n")); ctdb_ctrl_setrecmode(ctdb, TIMELIMIT(), options.pnn, CTDB_RECOVERY_ACTIVE); talloc_free(tmp_ctx); return -1; } DEBUG(DEBUG_ERR, ("Database wiped.\n")); talloc_free(tmp_ctx); return 0; } /* dump memory usage */ static int control_dumpmemory(struct ctdb_context *ctdb, int argc, const char **argv) { TDB_DATA data; int ret; int32_t res; char *errmsg; TALLOC_CTX *tmp_ctx = talloc_new(ctdb); ret = ctdb_control(ctdb, options.pnn, 0, CTDB_CONTROL_DUMP_MEMORY, 0, tdb_null, tmp_ctx, &data, &res, NULL, &errmsg); if (ret != 0 || res != 0) { DEBUG(DEBUG_ERR,("Failed to dump memory - %s\n", errmsg)); talloc_free(tmp_ctx); return -1; } write(1, data.dptr, data.dsize); talloc_free(tmp_ctx); return 0; } /* handler for memory dumps */ static void mem_dump_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *private_data) { write(1, data.dptr, data.dsize); exit(0); } /* dump memory usage on the recovery daemon */ static int control_rddumpmemory(struct ctdb_context *ctdb, int argc, const char **argv) { int ret; TDB_DATA data; struct srvid_request rd; rd.pnn = ctdb_get_pnn(ctdb); rd.srvid = getpid(); /* register a message port for receiveing the reply so that we can receive the reply */ ctdb_client_set_message_handler(ctdb, rd.srvid, mem_dump_handler, NULL); data.dptr = (uint8_t *)&rd; data.dsize = sizeof(rd); ret = ctdb_client_send_message(ctdb, options.pnn, CTDB_SRVID_MEM_DUMP, data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to send memdump request message to %u\n", options.pnn)); return -1; } /* this loop will terminate when we have received the reply */ while (1) { event_loop_once(ctdb->ev); } return 0; } /* send a message to a srvid */ static int control_msgsend(struct ctdb_context *ctdb, int argc, const char **argv) { unsigned long srvid; int ret; TDB_DATA data; if (argc < 2) { usage(); } srvid = strtoul(argv[0], NULL, 0); data.dptr = (uint8_t *)discard_const(argv[1]); data.dsize= strlen(argv[1]); ret = ctdb_client_send_message(ctdb, CTDB_BROADCAST_CONNECTED, srvid, data); if (ret != 0) { DEBUG(DEBUG_ERR,("Failed to send memdump request message to %u\n", options.pnn)); return -1; } return 0; } /* handler for msglisten */ static void msglisten_handler(struct ctdb_context *ctdb, uint64_t srvid, TDB_DATA data, void *private_data) { int i; printf("Message received: "); for (i=0;iev); } return 0; } /* list all nodes in the cluster we parse the nodes file directly */ static int control_listnodes(struct ctdb_context *ctdb, int argc, const char **argv) { TALLOC_CTX *mem_ctx = talloc_new(NULL); struct pnn_node *pnn_nodes; struct pnn_node *pnn_node; assert_single_node_only(); pnn_nodes = read_nodes_file(mem_ctx); if (pnn_nodes == NULL) { DEBUG(DEBUG_ERR,("Failed to read nodes file\n")); talloc_free(mem_ctx); return -1; } for(pnn_node=pnn_nodes;pnn_node;pnn_node=pnn_node->next) { ctdb_sock_addr addr; if (parse_ip(pnn_node->addr, NULL, 63999, &addr) == 0) { DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s' in nodes file\n", pnn_node->addr)); talloc_free(mem_ctx); return -1; } if (options.machinereadable){ printf(":%d:%s:\n", pnn_node->pnn, pnn_node->addr); } else { printf("%s\n", pnn_node->addr); } } talloc_free(mem_ctx); return 0; } /* reload the nodes file on the local node */ static int control_reload_nodes_file(struct ctdb_context *ctdb, int argc, const char **argv) { int i, ret; int mypnn; struct ctdb_node_map *nodemap=NULL; assert_single_node_only(); mypnn = ctdb_get_pnn(ctdb); ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap); if (ret != 0) { DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n")); return ret; } /* reload the nodes file on all remote nodes */ for (i=0;inum;i++) { if (nodemap->nodes[i].pnn == mypnn) { continue; } DEBUG(DEBUG_NOTICE, ("Reloading nodes file on node %u\n", nodemap->nodes[i].pnn)); ret = ctdb_ctrl_reload_nodes_file(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn); if (ret != 0) { DEBUG(DEBUG_ERR, ("ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually!\n", nodemap->nodes[i].pnn)); } } /* reload the nodes file on the local node */ DEBUG(DEBUG_NOTICE, ("Reloading nodes file on node %u\n", mypnn)); ret = ctdb_ctrl_reload_nodes_file(ctdb, TIMELIMIT(), mypnn); if (ret != 0) { DEBUG(DEBUG_ERR, ("ERROR: Failed to reload nodes file on node %u. You MUST fix that node manually!\n", mypnn)); } /* initiate a recovery */ control_recover(ctdb, argc, argv); return 0; } static const struct { const char *name; int (*fn)(struct ctdb_context *, int, const char **); bool auto_all; bool without_daemon; /* can be run without daemon running ? */ const char *msg; const char *args; } ctdb_commands[] = { { "version", control_version, true, true, "show version of ctdb" }, { "status", control_status, true, false, "show node status" }, { "uptime", control_uptime, true, false, "show node uptime" }, { "ping", control_ping, true, false, "ping all nodes" }, { "runstate", control_runstate, true, false, "get/check runstate of a node", "[setup|first_recovery|startup|running]" }, { "getvar", control_getvar, true, false, "get a tunable variable", ""}, { "setvar", control_setvar, true, false, "set a tunable variable", " "}, { "listvars", control_listvars, true, false, "list tunable variables"}, { "statistics", control_statistics, false, false, "show statistics" }, { "statisticsreset", control_statistics_reset, true, false, "reset statistics"}, { "stats", control_stats, false, false, "show rolling statistics", "[number of history records]" }, { "ip", control_ip, false, false, "show which public ip's that ctdb manages" }, { "ipinfo", control_ipinfo, true, false, "show details about a public ip that ctdb manages", "" }, { "ifaces", control_ifaces, true, false, "show which interfaces that ctdb manages" }, { "setifacelink", control_setifacelink, true, false, "set interface link status", " " }, { "process-exists", control_process_exists, true, false, "check if a process exists on a node", ""}, { "getdbmap", control_getdbmap, true, false, "show the database map" }, { "getdbstatus", control_getdbstatus, true, false, "show the status of a database", "" }, { "catdb", control_catdb, true, false, "dump a ctdb database" , ""}, { "cattdb", control_cattdb, true, false, "dump a local tdb database" , ""}, { "getmonmode", control_getmonmode, true, false, "show monitoring mode" }, { "getcapabilities", control_getcapabilities, true, false, "show node capabilities" }, { "pnn", control_pnn, true, false, "show the pnn of the currnet node" }, { "lvs", control_lvs, true, false, "show lvs configuration" }, { "lvsmaster", control_lvsmaster, true, false, "show which node is the lvs master" }, { "disablemonitor", control_disable_monmode,true, false, "set monitoring mode to DISABLE" }, { "enablemonitor", control_enable_monmode, true, false, "set monitoring mode to ACTIVE" }, { "setdebug", control_setdebug, true, false, "set debug level", "" }, { "getdebug", control_getdebug, true, false, "get debug level" }, { "getlog", control_getlog, true, false, "get the log data from the in memory ringbuffer", "[] [recoverd]" }, { "clearlog", control_clearlog, true, false, "clear the log data from the in memory ringbuffer", "[recoverd]" }, { "attach", control_attach, true, false, "attach to a database", " [persistent]" }, { "dumpmemory", control_dumpmemory, true, false, "dump memory map to stdout" }, { "rddumpmemory", control_rddumpmemory, true, false, "dump memory map from the recovery daemon to stdout" }, { "getpid", control_getpid, true, false, "get ctdbd process ID" }, { "disable", control_disable, true, false, "disable a nodes public IP" }, { "enable", control_enable, true, false, "enable a nodes public IP" }, { "stop", control_stop, true, false, "stop a node" }, { "continue", control_continue, true, false, "re-start a stopped node" }, { "ban", control_ban, true, false, "ban a node from the cluster", ""}, { "unban", control_unban, true, false, "unban a node" }, { "showban", control_showban, true, false, "show ban information"}, { "shutdown", control_shutdown, true, false, "shutdown ctdbd" }, { "recover", control_recover, true, false, "force recovery" }, { "sync", control_ipreallocate, false, false, "wait until ctdbd has synced all state changes" }, { "ipreallocate", control_ipreallocate, false, false, "force the recovery daemon to perform a ip reallocation procedure" }, { "thaw", control_thaw, true, false, "thaw databases", "[priority:1-3]" }, { "isnotrecmaster", control_isnotrecmaster, false, false, "check if the local node is recmaster or not" }, { "killtcp", kill_tcp, false, false, "kill a tcp connection.", "[ ]" }, { "gratiousarp", control_gratious_arp, false, false, "send a gratious arp", " " }, { "tickle", tickle_tcp, false, false, "send a tcp tickle ack", " " }, { "gettickles", control_get_tickles, false, false, "get the list of tickles registered for this ip", " []" }, { "addtickle", control_add_tickle, false, false, "add a tickle for this ip", ": :" }, { "deltickle", control_del_tickle, false, false, "delete a tickle from this ip", ": :" }, { "regsrvid", regsrvid, false, false, "register a server id", " " }, { "unregsrvid", unregsrvid, false, false, "unregister a server id", " " }, { "chksrvid", chksrvid, false, false, "check if a server id exists", " " }, { "getsrvids", getsrvids, false, false, "get a list of all server ids"}, { "check_srvids", check_srvids, false, false, "check if a srvid exists", "+" }, { "repack", ctdb_repack, false, false, "repack all databases", "[max_freelist]"}, { "listnodes", control_listnodes, false, true, "list all nodes in the cluster"}, { "reloadnodes", control_reload_nodes_file, false, false, "reload the nodes file and restart the transport on all nodes"}, { "moveip", control_moveip, false, false, "move/failover an ip address to another node", " "}, { "rebalanceip", control_rebalanceip, false, false, "release an ip from the node and let recd rebalance it", ""}, { "addip", control_addip, true, false, "add a ip address to a node", " "}, { "delip", control_delip, false, false, "delete an ip address from a node", ""}, { "eventscript", control_eventscript, true, false, "run the eventscript with the given parameters on a node", ""}, { "backupdb", control_backupdb, false, false, "backup the database into a file.", " "}, { "restoredb", control_restoredb, false, false, "restore the database from a file.", " [dbname]"}, { "dumpdbbackup", control_dumpdbbackup, false, true, "dump database backup from a file.", ""}, { "wipedb", control_wipedb, false, false, "wipe the contents of a database.", ""}, { "recmaster", control_recmaster, true, false, "show the pnn for the recovery master."}, { "scriptstatus", control_scriptstatus, true, false, "show the status of the monitoring scripts (or all scripts)", "[all]"}, { "enablescript", control_enablescript, true, false, "enable an eventscript", "