common/system: Add ctdb_set_process_name() function
[ambi/samba-autobuild/.git] / ctdb / common / system_linux.c
1 /* 
2    ctdb system specific code to manage raw sockets on linux
3
4    Copyright (C) Ronnie Sahlberg  2007
5    Copyright (C) Andrew Tridgell  2007
6
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.
11    
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.
16    
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/>.
19 */
20
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>
32
33 #ifndef ETHERTYPE_IP6
34 #define ETHERTYPE_IP6 0x86dd
35 #endif
36
37 /*
38   calculate the tcp checksum for tcp over ipv6
39 */
40 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
41 {
42         uint32_t phdr[2];
43         uint32_t sum = 0;
44         uint16_t sum2;
45
46         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
47         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
48
49         phdr[0] = htonl(n);
50         phdr[1] = htonl(ip6->ip6_nxt);
51         sum += uint16_checksum((uint16_t *)phdr, 8);
52
53         sum += uint16_checksum(data, n);
54
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;
61         }
62         return sum2;
63 }
64
65 /*
66   send gratuitous arp reply after we have taken over an ip address
67
68   saddr is the address we are trying to claim
69   iface is the interface name we will be using to claim the address
70  */
71 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
72 {
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 icmp6_hdr *icmp6;
79         struct ifreq if_hwaddr;
80         unsigned char buffer[78]; /* ipv6 neigh solicitation size */
81         char *ptr;
82         char bdcast[] = {0xff,0xff,0xff,0xff,0xff,0xff};
83         struct ifreq ifr;
84
85         ZERO_STRUCT(sall);
86
87         switch (addr->ip.sin_family) {
88         case AF_INET:
89                 s = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_ARP));
90                 if (s == -1){
91                         DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
92                         return -1;
93                 }
94
95                 DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
96                 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
97                 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
98                         DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
99                         close(s);
100                         return -1;
101                 }
102
103                 /* get the mac address */
104                 strcpy(if_hwaddr.ifr_name, iface);
105                 ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
106                 if ( ret < 0 ) {
107                         close(s);
108                         DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
109                         return -1;
110                 }
111                 if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
112                         DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
113                         close(s);
114                         return 0;
115                 }
116                 if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
117                         close(s);
118                         errno = EINVAL;
119                         DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
120                                  if_hwaddr.ifr_hwaddr.sa_family));
121                         return -1;
122                 }
123
124
125                 memset(buffer, 0 , 64);
126                 eh = (struct ether_header *)buffer;
127                 memset(eh->ether_dhost, 0xff, ETH_ALEN);
128                 memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
129                 eh->ether_type = htons(ETHERTYPE_ARP);
130         
131                 ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
132                 ah->ar_hrd = htons(ARPHRD_ETHER);
133                 ah->ar_pro = htons(ETH_P_IP);
134                 ah->ar_hln = ETH_ALEN;
135                 ah->ar_pln = 4;
136
137                 /* send a gratious arp */
138                 ah->ar_op  = htons(ARPOP_REQUEST);
139                 ptr = (char *)&ah[1];
140                 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
141                 ptr+=ETH_ALEN;
142                 memcpy(ptr, &addr->ip.sin_addr, 4);       
143                 ptr+=4;
144                 memset(ptr, 0, ETH_ALEN); 
145                 ptr+=ETH_ALEN;
146                 memcpy(ptr, &addr->ip.sin_addr, 4);       
147                 ptr+=4;
148         
149                 sall.sll_family = AF_PACKET;
150                 sall.sll_halen = 6;
151                 memcpy(&sall.sll_addr[0], bdcast, sall.sll_halen);
152                 sall.sll_protocol = htons(ETH_P_ALL);
153                 sall.sll_ifindex = ifr.ifr_ifindex;
154                 ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
155                 if (ret < 0 ){
156                         close(s);
157                         DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
158                         return -1;
159                 }       
160
161                 /* send unsolicited arp reply broadcast */
162                 ah->ar_op  = htons(ARPOP_REPLY);
163                 ptr = (char *)&ah[1];
164                 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
165                 ptr+=ETH_ALEN;
166                 memcpy(ptr, &addr->ip.sin_addr, 4);       
167                 ptr+=4;
168                 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
169                 ptr+=ETH_ALEN;
170                 memcpy(ptr, &addr->ip.sin_addr, 4);       
171                 ptr+=4;
172
173                 ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
174                 if (ret < 0 ){
175                         DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
176                         close(s);
177                         return -1;
178                 }
179
180                 close(s);
181                 break;
182         case AF_INET6:
183                 s = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_ARP));
184                 if (s == -1){
185                         DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
186                         return -1;
187                 }
188
189                 DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
190                 strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
191                 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
192                         DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
193                         close(s);
194                         return -1;
195                 }
196
197                 /* get the mac address */
198                 strcpy(if_hwaddr.ifr_name, iface);
199                 ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
200                 if ( ret < 0 ) {
201                         close(s);
202                         DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
203                         return -1;
204                 }
205                 if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
206                         DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
207                         close(s);
208                         return 0;
209                 }
210                 if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
211                         close(s);
212                         errno = EINVAL;
213                         DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
214                                  if_hwaddr.ifr_hwaddr.sa_family));
215                         return -1;
216                 }
217
218                 memset(buffer, 0 , sizeof(buffer));
219                 eh = (struct ether_header *)buffer;
220                 memset(eh->ether_dhost, 0xff, ETH_ALEN);
221                 memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
222                 eh->ether_type = htons(ETHERTYPE_IP6);
223
224                 ip6 = (struct ip6_hdr *)(eh+1);
225                 ip6->ip6_vfc  = 0x60;
226                 ip6->ip6_plen = htons(24);
227                 ip6->ip6_nxt  = IPPROTO_ICMPV6;
228                 ip6->ip6_hlim = 255;
229                 ip6->ip6_dst  = addr->ip6.sin6_addr;
230
231                 icmp6 = (struct icmp6_hdr *)(ip6+1);
232                 icmp6->icmp6_type = ND_NEIGHBOR_SOLICIT;
233                 icmp6->icmp6_code = 0;
234                 memcpy(&icmp6->icmp6_data32[1], &addr->ip6.sin6_addr, 16);
235
236                 icmp6->icmp6_cksum = tcp_checksum6((uint16_t *)icmp6, ntohs(ip6->ip6_plen), ip6);
237
238                 sall.sll_family = AF_PACKET;
239                 sall.sll_halen = 6;
240                 memcpy(&sall.sll_addr[0], bdcast, sall.sll_halen);
241                 sall.sll_protocol = htons(ETH_P_ALL);
242                 sall.sll_ifindex = ifr.ifr_ifindex;
243                 ret = sendto(s, buffer, 78, 0, (struct sockaddr *)&sall, sizeof(sall));
244                 if (ret < 0 ){
245                         close(s);
246                         DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
247                         return -1;
248                 }       
249
250                 close(s);
251                 break;
252         default:
253                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/ipv6 address (family is %u)\n", addr->ip.sin_family));
254                 return -1;
255         }
256
257         return 0;
258 }
259
260
261 /*
262   simple TCP checksum - assumes data is multiple of 2 bytes long
263  */
264 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
265 {
266         uint32_t sum = uint16_checksum(data, n);
267         uint16_t sum2;
268         sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
269                                sizeof(ip->saddr));
270         sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
271                                sizeof(ip->daddr));
272         sum += ip->protocol + n;
273         sum = (sum & 0xFFFF) + (sum >> 16);
274         sum = (sum & 0xFFFF) + (sum >> 16);
275         sum2 = htons(sum);
276         sum2 = ~sum2;
277         if (sum2 == 0) {
278                 return 0xFFFF;
279         }
280         return sum2;
281 }
282
283 /*
284   Send tcp segment from the specified IP/port to the specified
285   destination IP/port. 
286
287   This is used to trigger the receiving host into sending its own ACK,
288   which should trigger early detection of TCP reset by the client
289   after IP takeover
290
291   This can also be used to send RST segments (if rst is true) and also
292   if correct seq and ack numbers are provided.
293  */
294 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, 
295                       const ctdb_sock_addr *src,
296                       uint32_t seq, uint32_t ack, int rst)
297 {
298         int s;
299         int ret;
300         uint32_t one = 1;
301         uint16_t tmpport;
302         ctdb_sock_addr *tmpdest;
303         struct {
304                 struct iphdr ip;
305                 struct tcphdr tcp;
306         } ip4pkt;
307         struct {
308                 struct ip6_hdr ip6;
309                 struct tcphdr tcp;
310         } ip6pkt;
311
312         switch (src->ip.sin_family) {
313         case AF_INET:
314                 ZERO_STRUCT(ip4pkt);
315                 ip4pkt.ip.version  = 4;
316                 ip4pkt.ip.ihl      = sizeof(ip4pkt.ip)/4;
317                 ip4pkt.ip.tot_len  = htons(sizeof(ip4pkt));
318                 ip4pkt.ip.ttl      = 255;
319                 ip4pkt.ip.protocol = IPPROTO_TCP;
320                 ip4pkt.ip.saddr    = src->ip.sin_addr.s_addr;
321                 ip4pkt.ip.daddr    = dest->ip.sin_addr.s_addr;
322                 ip4pkt.ip.check    = 0;
323
324                 ip4pkt.tcp.source   = src->ip.sin_port;
325                 ip4pkt.tcp.dest     = dest->ip.sin_port;
326                 ip4pkt.tcp.seq      = seq;
327                 ip4pkt.tcp.ack_seq  = ack;
328                 ip4pkt.tcp.ack      = 1;
329                 if (rst) {
330                         ip4pkt.tcp.rst      = 1;
331                 }
332                 ip4pkt.tcp.doff     = sizeof(ip4pkt.tcp)/4;
333                 /* this makes it easier to spot in a sniffer */
334                 ip4pkt.tcp.window   = htons(1234);
335                 ip4pkt.tcp.check    = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
336
337                 /* open a raw socket to send this segment from */
338                 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
339                 if (s == -1) {
340                         DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
341                                  strerror(errno)));
342                         return -1;
343                 }
344
345                 ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
346                 if (ret != 0) {
347                         DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
348                                  strerror(errno)));
349                         close(s);
350                         return -1;
351                 }
352
353                 set_nonblocking(s);
354                 set_close_on_exec(s);
355
356                 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
357                              (const struct sockaddr *)&dest->ip,
358                              sizeof(dest->ip));
359                 close(s);
360                 if (ret != sizeof(ip4pkt)) {
361                         DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
362                         return -1;
363                 }
364                 break;
365         case AF_INET6:
366                 ZERO_STRUCT(ip6pkt);
367                 ip6pkt.ip6.ip6_vfc  = 0x60;
368                 ip6pkt.ip6.ip6_plen = htons(20);
369                 ip6pkt.ip6.ip6_nxt  = IPPROTO_TCP;
370                 ip6pkt.ip6.ip6_hlim = 64;
371                 ip6pkt.ip6.ip6_src  = src->ip6.sin6_addr;
372                 ip6pkt.ip6.ip6_dst  = dest->ip6.sin6_addr;
373
374                 ip6pkt.tcp.source   = src->ip6.sin6_port;
375                 ip6pkt.tcp.dest     = dest->ip6.sin6_port;
376                 ip6pkt.tcp.seq      = seq;
377                 ip6pkt.tcp.ack_seq  = ack;
378                 ip6pkt.tcp.ack      = 1;
379                 if (rst) {
380                         ip6pkt.tcp.rst      = 1;
381                 }
382                 ip6pkt.tcp.doff     = sizeof(ip6pkt.tcp)/4;
383                 /* this makes it easier to spot in a sniffer */
384                 ip6pkt.tcp.window   = htons(1234);
385                 ip6pkt.tcp.check    = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
386
387                 s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
388                 if (s == -1) {
389                         DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
390                         return -1;
391
392                 }
393                 /* sendto() dont like if the port is set and the socket is
394                    in raw mode.
395                 */
396                 tmpdest = discard_const(dest);
397                 tmpport = tmpdest->ip6.sin6_port;
398
399                 tmpdest->ip6.sin6_port = 0;
400                 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
401                              (const struct sockaddr *)&dest->ip6,
402                              sizeof(dest->ip6));
403                 tmpdest->ip6.sin6_port = tmpport;
404                 close(s);
405
406                 if (ret != sizeof(ip6pkt)) {
407                         DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
408                         return -1;
409                 }
410                 break;
411
412         default:
413                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
414                 return -1;
415         }
416
417         return 0;
418 }
419
420 /* 
421    This function is used to open a raw socket to capture from
422  */
423 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
424 {
425         int s;
426
427         /* Open a socket to capture all traffic */
428         s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
429         if (s == -1) {
430                 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
431                 return -1;
432         }
433
434         DEBUG(DEBUG_DEBUG, (__location__ " Created RAW SOCKET FD:%d for tcp tickle\n", s));
435
436         set_nonblocking(s);
437         set_close_on_exec(s);
438
439         return s;
440 }
441
442 /* 
443    This function is used to do any additional cleanup required when closing
444    a capture socket.
445    Note that the socket itself is closed automatically in the caller.
446  */
447 int ctdb_sys_close_capture_socket(void *private_data)
448 {
449         return 0;
450 }
451
452
453 /*
454   called when the raw socket becomes readable
455  */
456 int ctdb_sys_read_tcp_packet(int s, void *private_data, 
457                         ctdb_sock_addr *src, ctdb_sock_addr *dst,
458                         uint32_t *ack_seq, uint32_t *seq)
459 {
460         int ret;
461 #define RCVPKTSIZE 100
462         char pkt[RCVPKTSIZE];
463         struct ether_header *eth;
464         struct iphdr *ip;
465         struct ip6_hdr *ip6;
466         struct tcphdr *tcp;
467
468         ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
469         if (ret < sizeof(*eth)+sizeof(*ip)) {
470                 return -1;
471         }
472
473         /* Ethernet */
474         eth = (struct ether_header *)pkt;
475
476         /* we want either IPv4 or IPv6 */
477         if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
478                 /* IP */
479                 ip = (struct iphdr *)(eth+1);
480
481                 /* We only want IPv4 packets */
482                 if (ip->version != 4) {
483                         return -1;
484                 }
485                 /* Dont look at fragments */
486                 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
487                         return -1;
488                 }
489                 /* we only want TCP */
490                 if (ip->protocol != IPPROTO_TCP) {
491                         return -1;
492                 }
493
494                 /* make sure its not a short packet */
495                 if (offsetof(struct tcphdr, ack_seq) + 4 + 
496                     (ip->ihl*4) + sizeof(*eth) > ret) {
497                         return -1;
498                 }
499                 /* TCP */
500                 tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
501
502                 /* tell the caller which one we've found */
503                 src->ip.sin_family      = AF_INET;
504                 src->ip.sin_addr.s_addr = ip->saddr;
505                 src->ip.sin_port        = tcp->source;
506                 dst->ip.sin_family      = AF_INET;
507                 dst->ip.sin_addr.s_addr = ip->daddr;
508                 dst->ip.sin_port        = tcp->dest;
509                 *ack_seq                = tcp->ack_seq;
510                 *seq                    = tcp->seq;
511
512                 return 0;
513         } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
514                 /* IP6 */
515                 ip6 = (struct ip6_hdr *)(eth+1);
516
517                 /* we only want TCP */
518                 if (ip6->ip6_nxt != IPPROTO_TCP) {
519                         return -1;
520                 }
521
522                 /* TCP */
523                 tcp = (struct tcphdr *)(ip6+1);
524
525                 /* tell the caller which one we've found */
526                 src->ip6.sin6_family = AF_INET6;
527                 src->ip6.sin6_port   = tcp->source;
528                 src->ip6.sin6_addr   = ip6->ip6_src;
529
530                 dst->ip6.sin6_family = AF_INET6;
531                 dst->ip6.sin6_port   = tcp->dest;
532                 dst->ip6.sin6_addr   = ip6->ip6_dst;
533
534                 *ack_seq             = tcp->ack_seq;
535                 *seq                 = tcp->seq;
536
537                 return 0;
538         }
539
540         return -1;
541 }
542
543
544 bool ctdb_sys_check_iface_exists(const char *iface)
545 {
546         int s;
547         struct ifreq ifr;
548
549         s = socket(PF_PACKET, SOCK_RAW, 0);
550         if (s == -1){
551                 /* We dont know if the interface exists, so assume yes */
552                 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
553                 return true;
554         }
555
556         strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
557         if (ioctl(s, SIOCGIFINDEX, &ifr) < 0 && errno == ENODEV) {
558                 DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
559                 close(s);
560                 return false;
561         }
562         close(s);
563         
564         return true;
565 }
566
567 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
568 {
569         struct ucred cr;
570         socklen_t crl = sizeof(struct ucred);
571         int ret;
572         if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &crl) == 0)) {
573                 *peer_pid = cr.pid;
574         }
575         return ret;
576 }
577
578 /*
579  * Find the process name from process ID
580  */
581 char *ctdb_get_process_name(pid_t pid)
582 {
583         char path[32];
584         char buf[PATH_MAX];
585         char *ptr;
586         int n;
587
588         snprintf(path, sizeof(path), "/proc/%d/exe", pid);
589         n = readlink(path, buf, sizeof(buf));
590         if (n < 0) {
591                 return NULL;
592         }
593
594         /* Remove any extra fields */
595         buf[n] = '\0';
596         ptr = strtok(buf, " ");
597         return strdup(ptr);
598 }
599
600 /*
601  * Set process name
602  */
603 int ctdb_set_process_name(const char *name)
604 {
605         char procname[16];
606
607         strncpy(procname, name, 15);
608         return prctl(PR_SET_NAME, (unsigned long)procname, 0, 0, 0);
609 }
610
611 /*
612  * Parsing a line from /proc/locks,
613  */
614 static bool parse_proc_locks_line(char *line, pid_t *pid,
615                                   struct ctdb_lock_info *curlock)
616 {
617         char *ptr, *saveptr;
618
619         /* output of /proc/locks
620          *
621          * lock assigned
622          * 1: POSIX  ADVISORY  WRITE 25945 fd:00:6424820 212 212
623          *
624          * lock waiting
625          * 1: -> POSIX  ADVISORY  WRITE 25946 fd:00:6424820 212 212
626          */
627
628         /* Id: */
629         ptr = strtok_r(line, " ", &saveptr);
630         if (ptr == NULL) return false;
631
632         /* -> */
633         ptr = strtok_r(NULL, " ", &saveptr);
634         if (ptr == NULL) return false;
635         if (strcmp(ptr, "->") == 0) {
636                 curlock->waiting = true;
637                 ptr = strtok_r(NULL, " ", &saveptr);
638         } else {
639                 curlock->waiting = false;
640         }
641
642         /* POSIX */
643         if (ptr == NULL || strcmp(ptr, "POSIX") != 0) {
644                 return false;
645         }
646
647         /* ADVISORY */
648         ptr = strtok_r(NULL, " ", &saveptr);
649         if (ptr == NULL) return false;
650
651         /* WRITE */
652         ptr = strtok_r(NULL, " ", &saveptr);
653         if (ptr == NULL) return false;
654         if (strcmp(ptr, "READ") == 0) {
655                 curlock->read_only = true;
656         } else if (strcmp(ptr, "WRITE") == 0) {
657                 curlock->read_only = false;
658         } else {
659                 return false;
660         }
661
662         /* PID */
663         ptr = strtok_r(NULL, " ", &saveptr);
664         if (ptr == NULL) return false;
665         *pid = atoi(ptr);
666
667         /* MAJOR:MINOR:INODE */
668         ptr = strtok_r(NULL, " :", &saveptr);
669         if (ptr == NULL) return false;
670         ptr = strtok_r(NULL, " :", &saveptr);
671         if (ptr == NULL) return false;
672         ptr = strtok_r(NULL, " :", &saveptr);
673         if (ptr == NULL) return false;
674         curlock->inode = atol(ptr);
675
676         /* START OFFSET */
677         ptr = strtok_r(NULL, " ", &saveptr);
678         if (ptr == NULL) return false;
679         curlock->start = atol(ptr);
680
681         /* END OFFSET */
682         ptr = strtok_r(NULL, " ", &saveptr);
683         if (ptr == NULL) return false;
684         if (strncmp(ptr, "EOF", 3) == 0) {
685                 curlock->end = (off_t)-1;
686         } else {
687                 curlock->end = atol(ptr);
688         }
689
690         return true;
691 }
692
693 /*
694  * Find information of lock being waited on for given process ID
695  */
696 bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
697 {
698         FILE *fp;
699         struct ctdb_lock_info curlock;
700         pid_t pid;
701         char buf[1024];
702         char *ptr;
703         bool status = false;
704
705         if ((fp = fopen("/proc/locks", "r")) == NULL) {
706                 DEBUG(DEBUG_ERR, ("Failed to read locks information"));
707                 return false;
708         }
709         while ((ptr = fgets(buf, sizeof(buf), fp)) != NULL) {
710                 if (! parse_proc_locks_line(buf, &pid, &curlock)) {
711                         continue;
712                 }
713                 if (pid == req_pid && curlock.waiting) {
714                         *lock_info = curlock;
715                         status = true;
716                         break;
717                 }
718         }
719         fclose(fp);
720
721         return status;
722 }
723
724 /*
725  * Find process ID which holds an overlapping byte lock for required
726  * inode and byte range.
727  */
728 bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
729 {
730         FILE *fp;
731         struct ctdb_lock_info curlock;
732         pid_t pid;
733         char buf[1024];
734         char *ptr;
735         bool status = false;
736
737         if ((fp = fopen("/proc/locks", "r")) == NULL) {
738                 DEBUG(DEBUG_ERR, ("Failed to read locks information"));
739                 return false;
740         }
741         while ((ptr = fgets(buf, sizeof(buf), fp)) != NULL) {
742                 if (! parse_proc_locks_line(buf, &pid, &curlock)) {
743                         continue;
744                 }
745
746                 if (curlock.waiting) {
747                         continue;
748                 }
749
750                 if (curlock.inode != reqlock->inode) {
751                         continue;
752                 }
753
754                 if (curlock.start > reqlock->end ||
755                     curlock.end < reqlock->start) {
756                         /* Outside the required range */
757                         continue;
758                 }
759                 *blocker_pid = pid;
760                 status = true;
761                 break;
762         }
763         fclose(fp);
764
765         return status;
766 }