Merge in trunk.
[awesomized/libmemcached] / clients / memcp.cc
1 /* LibMemcached
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 *
8 * Summary:
9 *
10 */
11
12 #include "config.h"
13
14 #include <cerrno>
15 #include <climits>
16 #include <cstdio>
17 #include <cstdlib>
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 <sys/types.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31
32
33 #include <libmemcached/memcached.h>
34
35 #include "client_options.h"
36 #include "utilities.h"
37
38 #define PROGRAM_NAME "memcp"
39 #define PROGRAM_DESCRIPTION "Copy a set of files to a memcached cluster."
40
41 /* Prototypes */
42 static void options_parse(int argc, char *argv[]);
43
44 static bool opt_binary= 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 && (val == LONG_MAX || val == LONG_MIN))
65 || (errno != 0 && val == 0))
66 {
67 *error= true;
68 return EXIT_SUCCESS;
69 }
70
71 if (endptr == nptr)
72 {
73 *error= true;
74 return EXIT_SUCCESS;
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 initialize_sockets();
86
87 memcached_st *memc= memcached_create(NULL);
88 process_hash_option(memc, opt_hash);
89
90 if (opt_servers == NULL)
91 {
92 char *temp;
93
94 if ((temp= getenv("MEMCACHED_SERVERS")))
95 {
96 opt_servers= strdup(temp);
97 }
98 else
99 {
100 std::cerr << "No Servers provided" << std::endl;
101 exit(EXIT_FAILURE);
102 }
103 }
104
105 memcached_server_st *servers;
106 if (opt_servers)
107 {
108 servers= memcached_servers_parse(opt_servers);
109 }
110 else
111 {
112 servers= memcached_servers_parse(argv[--argc]);
113 }
114
115 memcached_server_push(memc, servers);
116 memcached_server_list_free(servers);
117 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL,
118 (uint64_t)opt_binary);
119
120 if (opt_username and LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
121 {
122 memcached_free(memc);
123 std::cerr << "--username was supplied, but binary was not built with SASL support." << std::endl;
124 return EXIT_FAILURE;
125 }
126
127 if (opt_username)
128 {
129 memcached_return_t ret;
130 if (memcached_failed(ret= memcached_set_sasl_auth_data(memc, opt_username, opt_passwd)))
131 {
132 std::cerr << memcached_last_error_message(memc) << std::endl;
133 memcached_free(memc);
134 return EXIT_FAILURE;
135 }
136 }
137
138 int exit_code= EXIT_SUCCESS;
139 while (optind < argc)
140 {
141 int fd= open(argv[optind], O_RDONLY);
142 if (fd < 0)
143 {
144 if (opt_verbose)
145 {
146 fprintf(stderr, "memcp: %s: %s\n", argv[optind], strerror(errno));
147 optind++;
148 }
149 exit_code= EXIT_FAILURE;
150 continue;
151 }
152
153 struct stat sbuf;
154 (void)fstat(fd, &sbuf);
155
156 char *ptr= rindex(argv[optind], '/');
157 if (ptr)
158 {
159 ptr++;
160 }
161 else
162 {
163 ptr= argv[optind];
164 }
165
166 if (opt_verbose)
167 {
168 static const char *opstr[] = { "set", "add", "replace" };
169 printf("op: %s\nsource file: %s\nlength: %lu\n"
170 "key: %s\nflags: %x\nexpires: %lu\n",
171 opstr[opt_method - OPT_SET], argv[optind], (unsigned long)sbuf.st_size,
172 ptr, opt_flags, (unsigned long)opt_expires);
173 }
174
175 char *file_buffer_ptr;
176 if ((file_buffer_ptr= (char *)malloc(sizeof(char) * (size_t)sbuf.st_size)) == NULL)
177 {
178 fprintf(stderr, "malloc: %s\n", strerror(errno));
179 exit(EXIT_FAILURE);
180 }
181
182 ssize_t read_length;
183 if ((read_length= read(fd, file_buffer_ptr, (size_t)sbuf.st_size)) == -1)
184 {
185 fprintf(stderr, "read: %s\n", strerror(errno));
186 exit(EXIT_FAILURE);
187 }
188
189 if (read_length != sbuf.st_size)
190 {
191 fprintf(stderr, "Failure reading from file\n");
192 exit(1);
193 }
194
195 memcached_return_t rc;
196 if (opt_method == OPT_ADD)
197 rc= memcached_add(memc, ptr, strlen(ptr),
198 file_buffer_ptr, (size_t)sbuf.st_size,
199 opt_expires, opt_flags);
200 else if (opt_method == OPT_REPLACE)
201 rc= memcached_replace(memc, ptr, strlen(ptr),
202 file_buffer_ptr, (size_t)sbuf.st_size,
203 opt_expires, opt_flags);
204 else
205 rc= memcached_set(memc, ptr, strlen(ptr),
206 file_buffer_ptr, (size_t)sbuf.st_size,
207 opt_expires, opt_flags);
208
209 if (rc != MEMCACHED_SUCCESS)
210 {
211 fprintf(stderr, "memcp: %s: memcache error %s",
212 ptr, memcached_strerror(memc, rc));
213 if (memcached_last_error_errno(memc))
214 fprintf(stderr, " system error %s", strerror(memcached_last_error_errno(memc)));
215 fprintf(stderr, "\n");
216
217 exit_code= EXIT_FAILURE;
218 }
219
220 free(file_buffer_ptr);
221 close(fd);
222 optind++;
223 }
224
225 memcached_free(memc);
226
227 if (opt_servers)
228 free(opt_servers);
229 if (opt_hash)
230 free(opt_hash);
231
232 return exit_code;
233 }
234
235 static void options_parse(int argc, char *argv[])
236 {
237 memcached_programs_help_st help_options[]=
238 {
239 {0},
240 };
241
242 static struct option long_options[]=
243 {
244 {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
245 {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
246 {(OPTIONSTRING)"quiet", no_argument, NULL, OPT_QUIET},
247 {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
248 {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
249 {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
250 {(OPTIONSTRING)"flag", required_argument, NULL, OPT_FLAG},
251 {(OPTIONSTRING)"expire", required_argument, NULL, OPT_EXPIRE},
252 {(OPTIONSTRING)"set", no_argument, NULL, OPT_SET},
253 {(OPTIONSTRING)"add", no_argument, NULL, OPT_ADD},
254 {(OPTIONSTRING)"replace", no_argument, NULL, OPT_REPLACE},
255 {(OPTIONSTRING)"hash", required_argument, NULL, OPT_HASH},
256 {(OPTIONSTRING)"binary", no_argument, NULL, OPT_BINARY},
257 {(OPTIONSTRING)"username", required_argument, NULL, OPT_USERNAME},
258 {(OPTIONSTRING)"password", required_argument, NULL, OPT_PASSWD},
259 {0, 0, 0, 0},
260 };
261
262 bool opt_version= false;
263 bool opt_help= false;
264 int option_index= 0;
265
266 while (1)
267 {
268 int option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index);
269
270 if (option_rv == -1)
271 break;
272
273 switch (option_rv)
274 {
275 case 0:
276 break;
277 case OPT_BINARY:
278 opt_binary= true;
279 break;
280
281 case OPT_VERBOSE: /* --verbose or -v */
282 opt_verbose= OPT_VERBOSE;
283 break;
284
285 case OPT_DEBUG: /* --debug or -d */
286 opt_verbose= OPT_DEBUG;
287 break;
288
289 case OPT_VERSION: /* --version or -V */
290 opt_version= true;
291 break;
292
293 case OPT_HELP: /* --help or -h */
294 opt_help= true;
295 break;
296
297 case OPT_SERVERS: /* --servers or -s */
298 opt_servers= strdup(optarg);
299 break;
300
301 case OPT_FLAG: /* --flag */
302 {
303 bool strtol_error;
304 opt_flags= (uint32_t)strtol_wrapper(optarg, 16, &strtol_error);
305 if (strtol_error == true)
306 {
307 fprintf(stderr, "Bad value passed via --flag\n");
308 exit(1);
309 }
310 }
311 break;
312
313 case OPT_EXPIRE: /* --expire */
314 {
315 bool strtol_error;
316 opt_expires= (time_t)strtol_wrapper(optarg, 16, &strtol_error);
317 if (strtol_error == true)
318 {
319 fprintf(stderr, "Bad value passed via --flag\n");
320 exit(1);
321 }
322 }
323 break;
324
325 case OPT_SET:
326 opt_method= OPT_SET;
327 break;
328
329 case OPT_REPLACE:
330 opt_method= OPT_REPLACE;
331 break;
332
333 case OPT_ADD:
334 opt_method= OPT_ADD;
335 break;
336
337 case OPT_HASH:
338 opt_hash= strdup(optarg);
339 break;
340
341 case OPT_USERNAME:
342 opt_username= optarg;
343 break;
344
345 case OPT_PASSWD:
346 opt_passwd= optarg;
347 break;
348
349 case OPT_QUIET:
350 close_stdio();
351 break;
352
353 case '?':
354 /* getopt_long already printed an error message. */
355 exit(1);
356 default:
357 abort();
358 }
359 }
360
361 if (opt_version)
362 {
363 version_command(PROGRAM_NAME);
364 exit(EXIT_SUCCESS);
365 }
366
367 if (opt_help)
368 {
369 help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
370 exit(EXIT_SUCCESS);
371 }
372 }