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