docs: bin/
[awesomized/libmemcached] / src / bin / memcp.cc
1 /* LibMemcached
2 * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
3 * Copyright (C) 2006-2009 Brian Aker
4 * All rights reserved.
5 *
6 * Use and distribution licensed under the BSD license. See
7 * the COPYING file in the parent directory for full text.
8 *
9 * Summary:
10 *
11 */
12
13 #include "mem_config.h"
14
15 #include <cerrno>
16 #include <climits>
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <iostream>
23 #ifdef HAVE_STRINGS_H
24 #include <strings.h>
25 #endif
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30
31 #include "libmemcached-1.0/memcached.h"
32
33 #include "client_options.h"
34 #include "utilities.h"
35
36 #define PROGRAM_NAME "memcp"
37 #define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
38
39 /* Prototypes */
40 static void options_parse(int argc, char *argv[]);
41
42 static bool opt_binary= false;
43 static bool opt_udp= false;
44 static bool opt_buffer= false;
45 static int opt_verbose= 0;
46 static char *opt_servers= NULL;
47 static char *opt_hash= NULL;
48 static int opt_method= OPT_SET;
49 static uint32_t opt_flags= 0;
50 static time_t opt_expires= 0;
51 static char *opt_username;
52 static char *opt_passwd;
53
54 static long strtol_wrapper(const char *nptr, int base, bool *error)
55 {
56 long val;
57 char *endptr;
58
59 errno= 0; /* To distinguish success/failure after call */
60 val= strtol(nptr, &endptr, base);
61
62 /* Check for various possible errors */
63
64 if ((errno == ERANGE and (val == LONG_MAX or val == LONG_MIN))
65 or (errno != 0 && val == 0))
66 {
67 *error= true;
68 return 0;
69 }
70
71 if (endptr == nptr)
72 {
73 *error= true;
74 return 0;
75 }
76
77 *error= false;
78 return val;
79 }
80
81 int main(int argc, char *argv[])
82 {
83
84 options_parse(argc, argv);
85
86 if (optind >= argc)
87 {
88 fprintf(stderr, "Expected argument after options\n");
89 exit(EXIT_FAILURE);
90 }
91
92 initialize_sockets();
93
94 memcached_st *memc= memcached_create(NULL);
95
96 if (opt_udp)
97 {
98 if (opt_verbose)
99 {
100 std::cout << "Enabling UDP" << std::endl;
101 }
102
103 if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, opt_udp)))
104 {
105 memcached_free(memc);
106 std::cerr << "Could not enable UDP protocol." << std::endl;
107 return EXIT_FAILURE;
108 }
109 }
110
111 if (opt_buffer)
112 {
113 if (opt_verbose)
114 {
115 std::cout << "Enabling MEMCACHED_BEHAVIOR_BUFFER_REQUESTS" << std::endl;
116 }
117
118 if (memcached_failed(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, opt_buffer)))
119 {
120 memcached_free(memc);
121 std::cerr << "Could not enable MEMCACHED_BEHAVIOR_BUFFER_REQUESTS." << std::endl;
122 return EXIT_FAILURE;
123 }
124 }
125
126 process_hash_option(memc, opt_hash);
127
128 if (opt_servers == NULL)
129 {
130 char *temp;
131
132 if ((temp= getenv("MEMCACHED_SERVERS")))
133 {
134 opt_servers= strdup(temp);
135 }
136 #if 0
137 else if (argc >= 1 and argv[--argc])
138 {
139 opt_servers= strdup(argv[argc]);
140 }
141 #endif
142
143 if (opt_servers == NULL)
144 {
145 std::cerr << "No Servers provided" << std::endl;
146 exit(EXIT_FAILURE);
147 }
148 }
149
150 memcached_server_st* servers= memcached_servers_parse(opt_servers);
151 if (servers == NULL or memcached_server_list_count(servers) == 0)
152 {
153 std::cerr << "Invalid server list provided:" << opt_servers << std::endl;
154 return EXIT_FAILURE;
155 }
156
157 memcached_server_push(memc, servers);
158 memcached_server_list_free(servers);
159 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, opt_binary);
160 if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
161 {
162 memcached_free(memc);
163 std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
164 return EXIT_FAILURE;
165 }
166
167 if (opt_username)
168 {
169 memcached_return_t ret;
170 if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
171 {
172 std::cerr << memcached_last_error_message(memc) << std::endl;
173 memcached_free(memc);
174 return EXIT_FAILURE;
175 }
176 }
177
178 int exit_code= EXIT_SUCCESS;
179 while (optind < argc)
180 {
181 int fd= open(argv[optind], O_RDONLY);
182 if (fd < 0)
183 {
184 std::cerr << "memcp " << argv[optind] << " " << strerror(errno) << std::endl;
185 optind++;
186 exit_code= EXIT_FAILURE;
187 continue;
188 }
189
190 struct stat sbuf;
191 if (fstat(fd, &sbuf) == -1)
192 {
193 std::cerr << "memcp " << argv[optind] << " " << strerror(errno) << std::endl;
194 optind++;
195 exit_code= EXIT_FAILURE;
196 continue;
197 }
198
199 char *ptr= rindex(argv[optind], '/');
200 if (ptr)
201 {
202 ptr++;
203 }
204 else
205 {
206 ptr= argv[optind];
207 }
208
209 if (opt_verbose)
210 {
211 static const char *opstr[] = { "set", "add", "replace" };
212 printf("op: %s\nsource file: %s\nlength: %lu\n"
213 "key: %s\nflags: %x\nexpires: %lu\n",
214 opstr[opt_method - OPT_SET], argv[optind], (unsigned long)sbuf.st_size,
215 ptr, opt_flags, (unsigned long)opt_expires);
216 }
217
218 // The file may be empty
219 char *file_buffer_ptr= NULL;
220 if (sbuf.st_size > 0)
221 {
222 if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
223 {
224 std::cerr << "Error allocating file buffer(" << strerror(errno) << ")" << std::endl;
225 close(fd);
226 exit(EXIT_FAILURE);
227 }
228
229 ssize_t read_length;
230 if ((read_length= ::read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1)
231 {
232 std::cerr << "Error while reading file " << file_buffer_ptr << " (" << strerror(errno) << ")" << std::endl;
233 close(fd);
234 free(file_buffer_ptr);
235 exit(EXIT_FAILURE);
236 }
237
238 if (read_length != sbuf.st_size)
239 {
240 std::cerr << "Failure while reading file. Read length was not equal to stat() length" << std::endl;
241 close(fd);
242 free(file_buffer_ptr);
243 exit(EXIT_FAILURE);
244 }
245 }
246
247 memcached_return_t rc;
248 if (opt_method == OPT_ADD)
249 {
250 rc= memcached_add(memc, ptr, strlen(ptr),
251 file_buffer_ptr, (size_t)sbuf.st_size,
252 opt_expires, opt_flags);
253 }
254 else if (opt_method == OPT_REPLACE)
255 {
256 rc= memcached_replace(memc, ptr, strlen(ptr),
257 file_buffer_ptr, (size_t)sbuf.st_size,
258 opt_expires, opt_flags);
259 }
260 else
261 {
262 rc= memcached_set(memc, ptr, strlen(ptr),
263 file_buffer_ptr, (size_t)sbuf.st_size,
264 opt_expires, opt_flags);
265 }
266
267 if (memcached_failed(rc))
268 {
269 std::cerr << "Error occrrured during memcached_set(): " << memcached_last_error_message(memc) << std::endl;
270 exit_code= EXIT_FAILURE;
271 }
272
273 ::free(file_buffer_ptr);
274 ::close(fd);
275 optind++;
276 }
277
278 if (opt_verbose)
279 {
280 std::cout << "Calling memcached_free()" << std::endl;
281 }
282
283 memcached_free(memc);
284
285 if (opt_servers)
286 {
287 free(opt_servers);
288 }
289
290 if (opt_hash)
291 {
292 free(opt_hash);
293 }
294
295 return exit_code;
296 }
297
298 static void options_parse(int argc, char *argv[])
299 {
300 memcached_programs_help_st help_options[]=
301 {
302 {0},
303 };
304
305 static struct option long_options[]=
306 {
307 {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
308 {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
309 {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
310 {(OPTIONSTRING)"udp", no_argument, NULL, OPT_UDP},
311 {(OPTIONSTRING)"buffer", no_argument, NULL, OPT_BUFFER},
312 {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
313 {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
314 {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
315 {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG},
316 {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
317 {(OPTIONSTRING)"set", no_argument, NULL, OPT_SET},
318 {(OPTIONSTRING)"add", no_argument, NULL, OPT_ADD},
319 {(OPTIONSTRING)"replace", no_argument, NULL, OPT_REPLACE},
320 {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
321 {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
322 {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
323 {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
324 {0, 0, 0, 0},
325 };
326
327 bool opt_version= false;
328 bool opt_help= false;
329 int option_index= 0;
330
331 while (1)
332 {
333 int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
334
335 if (option_rv == -1)
336 break;
337
338 switch (option_rv)
339 {
340 case 0:
341 break;
342
343 case OPT_BINARY:
344 opt_binary= true;
345 break;
346
347 case OPT_VERBOSE: /* --verbose or -v */
348 opt_verbose= OPT_VERBOSE;
349 break;
350
351 case OPT_DEBUG: /* --debug or -d */
352 opt_verbose= OPT_DEBUG;
353 break;
354
355 case OPT_VERSION: /* --version or -V */
356 opt_version= true;
357 break;
358
359 case OPT_HELP: /* --help or -h */
360 opt_help= true;
361 break;
362
363 case OPT_SERVERS: /* --servers or -s */
364 opt_servers= strdup(optarg);
365 break;
366
367 case OPT_FLAG: /* --flag */
368 {
369 bool strtol_error;
370 opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error);
371 if (strtol_error == true)
372 {
373 fprintf(stderr, "Bad value passed via --flag\n");
374 exit(1);
375 }
376 }
377 break;
378
379 case OPT_EXPIRE: /* --expire */
380 {
381 bool strtol_error;
382 opt_expires= (time_t)strtol_wrapper(optarg, 10, &strtol_error);
383 if (strtol_error == true)
384 {
385 fprintf(stderr, "Bad value passed via --expire\n");
386 exit(1);
387 }
388 }
389 break;
390
391 case OPT_SET:
392 opt_method= OPT_SET;
393 break;
394
395 case OPT_REPLACE:
396 opt_method= OPT_REPLACE;
397 break;
398
399 case OPT_ADD:
400 opt_method= OPT_ADD;
401 break;
402
403 case OPT_HASH:
404 opt_hash= strdup(optarg);
405 break;
406
407 case OPT_USERNAME:
408 opt_username= optarg;
409 break;
410
411 case OPT_PASSWD:
412 opt_passwd= optarg;
413 break;
414
415 case OPT_QUIET:
416 close_stdio();
417 break;
418
419 case OPT_UDP:
420 opt_udp= true;
421 break;
422
423 case OPT_BUFFER:
424 opt_buffer= true;
425 break;
426
427 case '?':
428 /* getopt_long already printed an error message. */
429 exit(1);
430 default:
431 abort();
432 }
433 }
434
435 if (opt_version)
436 {
437 version_command(PROGRAM_NAME);
438 exit(EXIT_SUCCESS);
439 }
440
441 if (opt_help)
442 {
443 help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
444 exit(EXIT_SUCCESS);
445 }
446 }