543c5d0eb7d65a5793f7ff796c75f39385bb55e1
[samba.git] / ctdb / server / ctdb_lock_helper.c
1 /*
2    ctdb lock helper
3
4    Copyright (C) Amitay Isaacs  2013
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/network.h"
23
24 #include <talloc.h>
25
26 #include "ctdb_private.h"
27
28 #include "common/system.h"
29
30 static char *progname = NULL;
31
32 static void send_result(int fd, char result)
33 {
34         sys_write(fd, &result, 1);
35         if (result == 1) {
36                 exit(1);
37         }
38 }
39
40
41 static void usage(void)
42 {
43         fprintf(stderr, "\n");
44         fprintf(stderr, "Usage: %s <log-fd> <ctdbd-pid> <output-fd> RECORD <db-path> <db-flags> <db-key>\n",
45                 progname);
46         fprintf(stderr, "       %s <log-fd> <ctdbd-pid> <output-fd> DB <db1-path> <db1-flags> [<db2-path> <db2-flags>...]\n",
47                 progname);
48 }
49
50 static uint8_t *hex_decode_talloc(TALLOC_CTX *mem_ctx,
51                                   const char *hex_in, size_t *len)
52 {
53         int i, num;
54         uint8_t *buffer;
55
56         *len = strlen(hex_in) / 2;
57         buffer = talloc_array(mem_ctx, unsigned char, *len);
58
59         for (i=0; i<*len; i++) {
60                 sscanf(&hex_in[i*2], "%02X", &num);
61                 buffer[i] = (uint8_t)num;
62         }
63
64         return buffer;
65 }
66
67 static int lock_record(const char *dbpath, const char *dbflags, const char *dbkey)
68 {
69         TDB_DATA key;
70         struct tdb_context *tdb;
71         int tdb_flags;
72
73         /* No error checking since CTDB always passes sane values */
74         tdb_flags = strtol(dbflags, NULL, 0);
75
76         /* Convert hex key to key */
77         if (strcmp(dbkey, "NULL") == 0) {
78                 key.dptr = NULL;
79                 key.dsize = 0;
80         } else {
81                 key.dptr = hex_decode_talloc(NULL, dbkey, &key.dsize);
82         }
83
84         tdb = tdb_open(dbpath, 0, tdb_flags, O_RDWR, 0600);
85         if (tdb == NULL) {
86                 fprintf(stderr, "%s: Error opening database %s\n", progname, dbpath);
87                 return 1;
88         }
89
90         if (tdb_chainlock(tdb, key) < 0) {
91                 fprintf(stderr, "%s: Error getting record lock (%s)\n",
92                         progname, tdb_errorstr(tdb));
93                 return 1;
94         }
95
96         return 0;
97
98 }
99
100
101 static int lock_db(const char *dbpath, const char *dbflags)
102 {
103         struct tdb_context *tdb;
104         int tdb_flags;
105
106         /* No error checking since CTDB always passes sane values */
107         tdb_flags = strtol(dbflags, NULL, 0);
108
109         tdb = tdb_open(dbpath, 0, tdb_flags, O_RDWR, 0600);
110         if (tdb == NULL) {
111                 fprintf(stderr, "%s: Error opening database %s\n", progname, dbpath);
112                 return 1;
113         }
114
115         if (tdb_lockall(tdb) < 0) {
116                 fprintf(stderr, "%s: Error getting db lock (%s)\n",
117                         progname, tdb_errorstr(tdb));
118                 return 1;
119         }
120
121         return 0;
122 }
123
124
125 int main(int argc, char *argv[])
126 {
127         int write_fd, log_fd;
128         char result = 0;
129         int ppid;
130         const char *lock_type;
131
132         progname = argv[0];
133
134         if (argc < 5) {
135                 usage();
136                 exit(1);
137         }
138
139         if (!set_scheduler()) {
140                 fprintf(stderr, "%s: Unable to set real-time scheduler priority\n",
141                         progname);
142         }
143
144         log_fd = atoi(argv[1]);
145         close(STDOUT_FILENO);
146         close(STDERR_FILENO);
147         dup2(log_fd, STDOUT_FILENO);
148         dup2(log_fd, STDERR_FILENO);
149         close(log_fd);
150
151         ppid = atoi(argv[2]);
152         write_fd = atoi(argv[3]);
153         lock_type = argv[4];
154
155         if (strcmp(lock_type, "RECORD") == 0) {
156                 if (argc != 8) {
157                         fprintf(stderr, "%s: Invalid number of arguments (%d)\n",
158                                 progname, argc);
159                         usage();
160                         exit(1);
161                 }
162                 result = lock_record(argv[5], argv[6], argv[7]);
163
164         } else if (strcmp(lock_type, "DB") == 0) {
165                 int n;
166
167                 /* If there are no databases specified, no need for lock */
168                 if (argc > 5) {
169                         for (n=5; n+1<argc; n+=2) {
170                                 result = lock_db(argv[n], argv[n+1]);
171                                 if (result != 0) {
172                                         break;
173                                 }
174                         }
175                 }
176
177         } else {
178                 fprintf(stderr, "%s: Invalid lock-type '%s'\n", progname, lock_type);
179                 usage();
180                 exit(1);
181         }
182
183         send_result(write_fd, result);
184
185         while (kill(ppid, 0) == 0 || errno != ESRCH) {
186                 sleep(5);
187         }
188         return 0;
189 }