ctdb-daemon: Fix typo in debug message
[Samba.git] / ctdb / common / system_linux.c
blobfdb8d1275799985a3a9aec30e559411f7876155b
1 /*
2 ctdb system specific code to manage raw sockets on linux
4 Copyright (C) Ronnie Sahlberg 2007
5 Copyright (C) Andrew Tridgell 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/network.h"
23 #include "system/filesys.h"
24 #include "system/wait.h"
25 #include "../include/ctdb_private.h"
26 #include <netinet/if_ether.h>
27 #include <netinet/ip6.h>
28 #include <netinet/icmp6.h>
29 #include <net/if_arp.h>
30 #include <netpacket/packet.h>
31 #include <sys/prctl.h>
33 #ifndef ETHERTYPE_IP6
34 #define ETHERTYPE_IP6 0x86dd
35 #endif
38 calculate the tcp checksum for tcp over ipv6
40 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
42 uint32_t phdr[2];
43 uint32_t sum = 0;
44 uint16_t sum2;
46 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
47 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
49 phdr[0] = htonl(n);
50 phdr[1] = htonl(ip6->ip6_nxt);
51 sum += uint16_checksum((uint16_t *)phdr, 8);
53 sum += uint16_checksum(data, n);
55 sum = (sum & 0xFFFF) + (sum >> 16);
56 sum = (sum & 0xFFFF) + (sum >> 16);
57 sum2 = htons(sum);
58 sum2 = ~sum2;
59 if (sum2 == 0) {
60 return 0xFFFF;
62 return sum2;
66 send gratuitous arp reply after we have taken over an ip address
68 saddr is the address we are trying to claim
69 iface is the interface name we will be using to claim the address
71 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
73 int s, ret;
74 struct sockaddr_ll sall;
75 struct ether_header *eh;
76 struct arphdr *ah;
77 struct ip6_hdr *ip6;
78 struct nd_neighbor_advert *nd_na;
79 struct nd_opt_hdr *nd_oh;
80 struct ifreq if_hwaddr;
81 /* Size of IPv6 neighbor advertisement (with option) */
82 unsigned char buffer[sizeof(struct ether_header) +
83 sizeof(struct ip6_hdr) +
84 sizeof(struct nd_neighbor_advert) +
85 sizeof(struct nd_opt_hdr) + ETH_ALEN];
86 char *ptr;
87 char bdcast[] = {0xff,0xff,0xff,0xff,0xff,0xff};
88 struct ifreq ifr;
90 ZERO_STRUCT(sall);
91 ZERO_STRUCT(ifr);
92 ZERO_STRUCT(if_hwaddr);
94 switch (addr->ip.sin_family) {
95 case AF_INET:
96 s = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_ARP));
97 if (s == -1){
98 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
99 return -1;
102 DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
103 strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
104 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
105 DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
106 close(s);
107 return -1;
110 /* get the mac address */
111 strncpy(if_hwaddr.ifr_name, iface, sizeof(if_hwaddr.ifr_name)-1);
112 ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
113 if ( ret < 0 ) {
114 close(s);
115 DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
116 return -1;
118 if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
119 DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
120 close(s);
121 return 0;
123 if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
124 close(s);
125 errno = EINVAL;
126 DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
127 if_hwaddr.ifr_hwaddr.sa_family));
128 return -1;
132 memset(buffer, 0 , 64);
133 eh = (struct ether_header *)buffer;
134 memset(eh->ether_dhost, 0xff, ETH_ALEN);
135 memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
136 eh->ether_type = htons(ETHERTYPE_ARP);
138 ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
139 ah->ar_hrd = htons(ARPHRD_ETHER);
140 ah->ar_pro = htons(ETH_P_IP);
141 ah->ar_hln = ETH_ALEN;
142 ah->ar_pln = 4;
144 /* send a gratious arp */
145 ah->ar_op = htons(ARPOP_REQUEST);
146 ptr = (char *)&ah[1];
147 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
148 ptr+=ETH_ALEN;
149 memcpy(ptr, &addr->ip.sin_addr, 4);
150 ptr+=4;
151 memset(ptr, 0, ETH_ALEN);
152 ptr+=ETH_ALEN;
153 memcpy(ptr, &addr->ip.sin_addr, 4);
154 ptr+=4;
156 sall.sll_family = AF_PACKET;
157 sall.sll_halen = 6;
158 memcpy(&sall.sll_addr[0], bdcast, sall.sll_halen);
159 sall.sll_protocol = htons(ETH_P_ALL);
160 sall.sll_ifindex = ifr.ifr_ifindex;
161 ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
162 if (ret < 0 ){
163 close(s);
164 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
165 return -1;
168 /* send unsolicited arp reply broadcast */
169 ah->ar_op = htons(ARPOP_REPLY);
170 ptr = (char *)&ah[1];
171 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
172 ptr+=ETH_ALEN;
173 memcpy(ptr, &addr->ip.sin_addr, 4);
174 ptr+=4;
175 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
176 ptr+=ETH_ALEN;
177 memcpy(ptr, &addr->ip.sin_addr, 4);
178 ptr+=4;
180 ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
181 if (ret < 0 ){
182 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
183 close(s);
184 return -1;
187 close(s);
188 break;
189 case AF_INET6:
190 s = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_ARP));
191 if (s == -1){
192 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
193 return -1;
196 DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
197 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
198 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
199 DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
200 close(s);
201 return -1;
204 /* get the mac address */
205 strncpy(if_hwaddr.ifr_name, iface, sizeof(if_hwaddr.ifr_name)-1);
206 ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
207 if ( ret < 0 ) {
208 close(s);
209 DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
210 return -1;
212 if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
213 DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
214 close(s);
215 return 0;
217 if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
218 close(s);
219 errno = EINVAL;
220 DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
221 if_hwaddr.ifr_hwaddr.sa_family));
222 return -1;
225 memset(buffer, 0 , sizeof(buffer));
226 eh = (struct ether_header *)buffer;
227 /* Ethernet multicast: 33:33:00:00:00:01 (see RFC2464,
228 * section 7) - note zeroes above! */
229 eh->ether_dhost[0] = eh->ether_dhost[1] = 0x33;
230 eh->ether_dhost[5] = 0x01;
231 memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
232 eh->ether_type = htons(ETHERTYPE_IP6);
234 ip6 = (struct ip6_hdr *)(eh+1);
235 ip6->ip6_vfc = 0x60;
236 ip6->ip6_plen = htons(sizeof(*nd_na) +
237 sizeof(struct nd_opt_hdr) +
238 ETH_ALEN);
239 ip6->ip6_nxt = IPPROTO_ICMPV6;
240 ip6->ip6_hlim = 255;
241 ip6->ip6_src = addr->ip6.sin6_addr;
242 /* all-nodes multicast */
243 inet_pton(AF_INET6, "ff02::1", &ip6->ip6_dst);
245 nd_na = (struct nd_neighbor_advert *)(ip6+1);
246 nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
247 nd_na->nd_na_code = 0;
248 nd_na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
249 nd_na->nd_na_target = addr->ip6.sin6_addr;
250 /* Option: Target link-layer address */
251 nd_oh = (struct nd_opt_hdr *)(nd_na+1);
252 nd_oh->nd_opt_type = ND_OPT_TARGET_LINKADDR;
253 nd_oh->nd_opt_len = 1;
254 memcpy(&(nd_oh+1)[0], if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
256 nd_na->nd_na_cksum = tcp_checksum6((uint16_t *)nd_na,
257 ntohs(ip6->ip6_plen), ip6);
259 sall.sll_family = AF_PACKET;
260 sall.sll_halen = 6;
261 memcpy(&sall.sll_addr[0], &eh->ether_dhost[0], sall.sll_halen);
262 sall.sll_protocol = htons(ETH_P_ALL);
263 sall.sll_ifindex = ifr.ifr_ifindex;
264 ret = sendto(s, buffer, sizeof(buffer),
265 0, (struct sockaddr *)&sall, sizeof(sall));
266 if (ret < 0 ){
267 close(s);
268 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
269 return -1;
272 close(s);
273 break;
274 default:
275 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/ipv6 address (family is %u)\n", addr->ip.sin_family));
276 return -1;
279 return 0;
284 simple TCP checksum - assumes data is multiple of 2 bytes long
286 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
288 uint32_t sum = uint16_checksum(data, n);
289 uint16_t sum2;
290 sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
291 sizeof(ip->saddr));
292 sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
293 sizeof(ip->daddr));
294 sum += ip->protocol + n;
295 sum = (sum & 0xFFFF) + (sum >> 16);
296 sum = (sum & 0xFFFF) + (sum >> 16);
297 sum2 = htons(sum);
298 sum2 = ~sum2;
299 if (sum2 == 0) {
300 return 0xFFFF;
302 return sum2;
306 Send tcp segment from the specified IP/port to the specified
307 destination IP/port.
309 This is used to trigger the receiving host into sending its own ACK,
310 which should trigger early detection of TCP reset by the client
311 after IP takeover
313 This can also be used to send RST segments (if rst is true) and also
314 if correct seq and ack numbers are provided.
316 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
317 const ctdb_sock_addr *src,
318 uint32_t seq, uint32_t ack, int rst)
320 int s;
321 int ret;
322 uint32_t one = 1;
323 uint16_t tmpport;
324 ctdb_sock_addr *tmpdest;
325 struct {
326 struct iphdr ip;
327 struct tcphdr tcp;
328 } ip4pkt;
329 struct {
330 struct ip6_hdr ip6;
331 struct tcphdr tcp;
332 } ip6pkt;
334 switch (src->ip.sin_family) {
335 case AF_INET:
336 ZERO_STRUCT(ip4pkt);
337 ip4pkt.ip.version = 4;
338 ip4pkt.ip.ihl = sizeof(ip4pkt.ip)/4;
339 ip4pkt.ip.tot_len = htons(sizeof(ip4pkt));
340 ip4pkt.ip.ttl = 255;
341 ip4pkt.ip.protocol = IPPROTO_TCP;
342 ip4pkt.ip.saddr = src->ip.sin_addr.s_addr;
343 ip4pkt.ip.daddr = dest->ip.sin_addr.s_addr;
344 ip4pkt.ip.check = 0;
346 ip4pkt.tcp.source = src->ip.sin_port;
347 ip4pkt.tcp.dest = dest->ip.sin_port;
348 ip4pkt.tcp.seq = seq;
349 ip4pkt.tcp.ack_seq = ack;
350 ip4pkt.tcp.ack = 1;
351 if (rst) {
352 ip4pkt.tcp.rst = 1;
354 ip4pkt.tcp.doff = sizeof(ip4pkt.tcp)/4;
355 /* this makes it easier to spot in a sniffer */
356 ip4pkt.tcp.window = htons(1234);
357 ip4pkt.tcp.check = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
359 /* open a raw socket to send this segment from */
360 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
361 if (s == -1) {
362 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
363 strerror(errno)));
364 return -1;
367 ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
368 if (ret != 0) {
369 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
370 strerror(errno)));
371 close(s);
372 return -1;
375 set_nonblocking(s);
376 set_close_on_exec(s);
378 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
379 (const struct sockaddr *)&dest->ip,
380 sizeof(dest->ip));
381 close(s);
382 if (ret != sizeof(ip4pkt)) {
383 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
384 return -1;
386 break;
387 case AF_INET6:
388 ZERO_STRUCT(ip6pkt);
389 ip6pkt.ip6.ip6_vfc = 0x60;
390 ip6pkt.ip6.ip6_plen = htons(20);
391 ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
392 ip6pkt.ip6.ip6_hlim = 64;
393 ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
394 ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
396 ip6pkt.tcp.source = src->ip6.sin6_port;
397 ip6pkt.tcp.dest = dest->ip6.sin6_port;
398 ip6pkt.tcp.seq = seq;
399 ip6pkt.tcp.ack_seq = ack;
400 ip6pkt.tcp.ack = 1;
401 if (rst) {
402 ip6pkt.tcp.rst = 1;
404 ip6pkt.tcp.doff = sizeof(ip6pkt.tcp)/4;
405 /* this makes it easier to spot in a sniffer */
406 ip6pkt.tcp.window = htons(1234);
407 ip6pkt.tcp.check = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
409 s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
410 if (s == -1) {
411 DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
412 return -1;
415 /* sendto() dont like if the port is set and the socket is
416 in raw mode.
418 tmpdest = discard_const(dest);
419 tmpport = tmpdest->ip6.sin6_port;
421 tmpdest->ip6.sin6_port = 0;
422 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
423 (const struct sockaddr *)&dest->ip6,
424 sizeof(dest->ip6));
425 tmpdest->ip6.sin6_port = tmpport;
426 close(s);
428 if (ret != sizeof(ip6pkt)) {
429 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
430 return -1;
432 break;
434 default:
435 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
436 return -1;
439 return 0;
443 This function is used to open a raw socket to capture from
445 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
447 int s;
449 /* Open a socket to capture all traffic */
450 s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
451 if (s == -1) {
452 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
453 return -1;
456 DEBUG(DEBUG_DEBUG, (__location__ " Created RAW SOCKET FD:%d for tcp tickle\n", s));
458 set_nonblocking(s);
459 set_close_on_exec(s);
461 return s;
465 This function is used to do any additional cleanup required when closing
466 a capture socket.
467 Note that the socket itself is closed automatically in the caller.
469 int ctdb_sys_close_capture_socket(void *private_data)
471 return 0;
476 called when the raw socket becomes readable
478 int ctdb_sys_read_tcp_packet(int s, void *private_data,
479 ctdb_sock_addr *src, ctdb_sock_addr *dst,
480 uint32_t *ack_seq, uint32_t *seq)
482 int ret;
483 #define RCVPKTSIZE 100
484 char pkt[RCVPKTSIZE];
485 struct ether_header *eth;
486 struct iphdr *ip;
487 struct ip6_hdr *ip6;
488 struct tcphdr *tcp;
490 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
491 if (ret < sizeof(*eth)+sizeof(*ip)) {
492 return -1;
495 /* Ethernet */
496 eth = (struct ether_header *)pkt;
498 /* we want either IPv4 or IPv6 */
499 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
500 /* IP */
501 ip = (struct iphdr *)(eth+1);
503 /* We only want IPv4 packets */
504 if (ip->version != 4) {
505 return -1;
507 /* Dont look at fragments */
508 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
509 return -1;
511 /* we only want TCP */
512 if (ip->protocol != IPPROTO_TCP) {
513 return -1;
516 /* make sure its not a short packet */
517 if (offsetof(struct tcphdr, ack_seq) + 4 +
518 (ip->ihl*4) + sizeof(*eth) > ret) {
519 return -1;
521 /* TCP */
522 tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
524 /* tell the caller which one we've found */
525 src->ip.sin_family = AF_INET;
526 src->ip.sin_addr.s_addr = ip->saddr;
527 src->ip.sin_port = tcp->source;
528 dst->ip.sin_family = AF_INET;
529 dst->ip.sin_addr.s_addr = ip->daddr;
530 dst->ip.sin_port = tcp->dest;
531 *ack_seq = tcp->ack_seq;
532 *seq = tcp->seq;
534 return 0;
535 } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
536 /* IP6 */
537 ip6 = (struct ip6_hdr *)(eth+1);
539 /* we only want TCP */
540 if (ip6->ip6_nxt != IPPROTO_TCP) {
541 return -1;
544 /* TCP */
545 tcp = (struct tcphdr *)(ip6+1);
547 /* tell the caller which one we've found */
548 src->ip6.sin6_family = AF_INET6;
549 src->ip6.sin6_port = tcp->source;
550 src->ip6.sin6_addr = ip6->ip6_src;
552 dst->ip6.sin6_family = AF_INET6;
553 dst->ip6.sin6_port = tcp->dest;
554 dst->ip6.sin6_addr = ip6->ip6_dst;
556 *ack_seq = tcp->ack_seq;
557 *seq = tcp->seq;
559 return 0;
562 return -1;
566 bool ctdb_sys_check_iface_exists(const char *iface)
568 int s;
569 struct ifreq ifr;
571 s = socket(PF_PACKET, SOCK_RAW, 0);
572 if (s == -1){
573 /* We dont know if the interface exists, so assume yes */
574 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
575 return true;
578 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
579 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0 && errno == ENODEV) {
580 DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
581 close(s);
582 return false;
584 close(s);
586 return true;
589 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
591 struct ucred cr;
592 socklen_t crl = sizeof(struct ucred);
593 int ret;
594 if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &crl) == 0)) {
595 *peer_pid = cr.pid;
597 return ret;
601 * Find the process name from process ID
603 char *ctdb_get_process_name(pid_t pid)
605 char path[32];
606 char buf[PATH_MAX];
607 char *ptr;
608 int n;
610 snprintf(path, sizeof(path), "/proc/%d/exe", pid);
611 n = readlink(path, buf, sizeof(buf)-1);
612 if (n < 0) {
613 return NULL;
616 /* Remove any extra fields */
617 buf[n] = '\0';
618 ptr = strtok(buf, " ");
619 return (ptr == NULL ? ptr : strdup(ptr));
623 * Set process name
625 int ctdb_set_process_name(const char *name)
627 char procname[16];
629 strncpy(procname, name, 15);
630 procname[15] = '\0';
631 return prctl(PR_SET_NAME, (unsigned long)procname, 0, 0, 0);
635 * Parsing a line from /proc/locks,
637 static bool parse_proc_locks_line(char *line, pid_t *pid,
638 struct ctdb_lock_info *curlock)
640 char *ptr, *saveptr;
642 /* output of /proc/locks
644 * lock assigned
645 * 1: POSIX ADVISORY WRITE 25945 fd:00:6424820 212 212
647 * lock waiting
648 * 1: -> POSIX ADVISORY WRITE 25946 fd:00:6424820 212 212
651 /* Id: */
652 ptr = strtok_r(line, " ", &saveptr);
653 if (ptr == NULL) return false;
655 /* -> */
656 ptr = strtok_r(NULL, " ", &saveptr);
657 if (ptr == NULL) return false;
658 if (strcmp(ptr, "->") == 0) {
659 curlock->waiting = true;
660 ptr = strtok_r(NULL, " ", &saveptr);
661 } else {
662 curlock->waiting = false;
665 /* POSIX */
666 if (ptr == NULL || strcmp(ptr, "POSIX") != 0) {
667 return false;
670 /* ADVISORY */
671 ptr = strtok_r(NULL, " ", &saveptr);
672 if (ptr == NULL) return false;
674 /* WRITE */
675 ptr = strtok_r(NULL, " ", &saveptr);
676 if (ptr == NULL) return false;
677 if (strcmp(ptr, "READ") == 0) {
678 curlock->read_only = true;
679 } else if (strcmp(ptr, "WRITE") == 0) {
680 curlock->read_only = false;
681 } else {
682 return false;
685 /* PID */
686 ptr = strtok_r(NULL, " ", &saveptr);
687 if (ptr == NULL) return false;
688 *pid = atoi(ptr);
690 /* MAJOR:MINOR:INODE */
691 ptr = strtok_r(NULL, " :", &saveptr);
692 if (ptr == NULL) return false;
693 ptr = strtok_r(NULL, " :", &saveptr);
694 if (ptr == NULL) return false;
695 ptr = strtok_r(NULL, " :", &saveptr);
696 if (ptr == NULL) return false;
697 curlock->inode = atol(ptr);
699 /* START OFFSET */
700 ptr = strtok_r(NULL, " ", &saveptr);
701 if (ptr == NULL) return false;
702 curlock->start = atol(ptr);
704 /* END OFFSET */
705 ptr = strtok_r(NULL, " ", &saveptr);
706 if (ptr == NULL) return false;
707 if (strncmp(ptr, "EOF", 3) == 0) {
708 curlock->end = (off_t)-1;
709 } else {
710 curlock->end = atol(ptr);
713 return true;
717 * Find information of lock being waited on for given process ID
719 bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
721 FILE *fp;
722 struct ctdb_lock_info curlock;
723 pid_t pid;
724 char buf[1024];
725 bool status = false;
727 if ((fp = fopen("/proc/locks", "r")) == NULL) {
728 DEBUG(DEBUG_ERR, ("Failed to read locks information"));
729 return false;
731 while (fgets(buf, sizeof(buf), fp) != NULL) {
732 if (! parse_proc_locks_line(buf, &pid, &curlock)) {
733 continue;
735 if (pid == req_pid && curlock.waiting) {
736 *lock_info = curlock;
737 status = true;
738 break;
741 fclose(fp);
743 return status;
747 * Find process ID which holds an overlapping byte lock for required
748 * inode and byte range.
750 bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
752 FILE *fp;
753 struct ctdb_lock_info curlock;
754 pid_t pid;
755 char buf[1024];
756 bool status = false;
758 if ((fp = fopen("/proc/locks", "r")) == NULL) {
759 DEBUG(DEBUG_ERR, ("Failed to read locks information"));
760 return false;
762 while (fgets(buf, sizeof(buf), fp) != NULL) {
763 if (! parse_proc_locks_line(buf, &pid, &curlock)) {
764 continue;
767 if (curlock.waiting) {
768 continue;
771 if (curlock.inode != reqlock->inode) {
772 continue;
775 if (curlock.start > reqlock->end ||
776 curlock.end < reqlock->start) {
777 /* Outside the required range */
778 continue;
780 *blocker_pid = pid;
781 status = true;
782 break;
784 fclose(fp);
786 return status;