xref: /3.0.3-GA/memcached/programs/mcctl.c (revision b449bca0)
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2014 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18/* mcctl - Utility program to perform IOCTL-style operations on a memcached
19 *         process.
20 */
21
22#include "config.h"
23
24#include <memcached/protocol_binary.h>
25#include <memcached/openssl.h>
26#include <platform/platform.h>
27
28#include <getopt.h>
29#include <stdlib.h>
30#include <stdio.h>
31
32#include <memcached/util.h>
33#include "utilities.h"
34
35/**
36 * Sets a property (to the specified value).
37 * @param bio connection to the server.
38 * @param property the name of the property to set.
39 * @param value value to set the property to (NULL == no value).
40 */
41static int ioctl_set(BIO *bio, const char *property, const char* value)
42{
43    char *buffer = NULL;
44    uint16_t keylen = 0;
45    uint32_t valuelen = 0;
46    int result;
47    protocol_binary_request_ioctl_set request;
48    protocol_binary_response_no_extras response;
49    protocol_binary_response_status status;
50
51    if (property != NULL) {
52        keylen = (uint16_t)strlen(property);
53    }
54    if (value != NULL) {
55        valuelen = (uint32_t)strlen(value);
56    }
57
58    memset(&request, 0, sizeof(request));
59    request.message.header.request.magic = PROTOCOL_BINARY_REQ;
60    request.message.header.request.opcode = PROTOCOL_BINARY_CMD_IOCTL_SET;
61    request.message.header.request.keylen = htons(keylen);
62    request.message.header.request.bodylen = htonl(valuelen);
63
64    ensure_send(bio, &request, sizeof(request));
65    if (keylen > 0) {
66        ensure_send(bio, property, keylen);
67    }
68    if (valuelen > 0) {
69        ensure_send(bio, value, valuelen);
70    }
71
72    ensure_recv(bio, &response, sizeof(response.bytes));
73    if (response.message.header.response.bodylen != 0) {
74        valuelen = ntohl(response.message.header.response.bodylen);
75        buffer = malloc(valuelen);
76        if (buffer == NULL) {
77            fprintf(stderr, "Failed to allocate memory for set response\n");
78            exit(EXIT_FAILURE);
79        }
80        ensure_recv(bio, buffer, valuelen);
81    }
82    status = htons(response.message.header.response.status);
83    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
84        result = 0;
85    } else {
86        fprintf(stderr, "Error from server: %s\n",
87                memcached_protocol_errcode_2_text(status));
88        result = 1;
89    }
90
91    if (buffer != NULL) {
92        fwrite(buffer, valuelen, 1, stdout);
93        fputs("\n", stdout);
94        fflush(stdout);
95        free(buffer);
96    }
97    return result;
98}
99
100/**
101 * Gets a property
102 * @param bio connection to the server.
103 * @param property the name of the property to get.
104 */
105static int ioctl_get(BIO *bio, const char *property)
106{
107    return 0;
108}
109
110static int usage() {
111    fprintf(stderr,
112            "Usage: mcctl [-h host[:port]] [-p port] [-u user] [-P pass] [-s] <get|set> property [value]\n"
113            "\n"
114            "    get <property>           Returns the value of the given property.\n"
115            "    set <property> [value]   Sets `property` to the given value.\n");
116    return EXIT_FAILURE;
117}
118
119int main(int argc, char** argv) {
120    int cmd;
121    const char *port = "11210";
122    const char *host = "localhost";
123    const char *user = NULL;
124    const char *pass = NULL;
125    int secure = 0;
126    char *ptr;
127    SSL_CTX* ctx;
128    BIO* bio;
129    int result = EXIT_FAILURE;
130
131    /* Initialize the socket subsystem */
132    cb_initialize_sockets();
133
134    while ((cmd = getopt(argc, argv, "h:p:u:P:s")) != EOF) {
135        switch (cmd) {
136        case 'h' :
137            host = optarg;
138            ptr = strchr(optarg, ':');
139            if (ptr != NULL) {
140                *ptr = '\0';
141                port = ptr + 1;
142            }
143            break;
144        case 'p':
145            port = optarg;
146            break;
147        case 'u' :
148            user = optarg;
149            break;
150        case 'P':
151            pass = optarg;
152            break;
153        case 's':
154            secure = 1;
155            break;
156        default:
157            return usage();
158        }
159    }
160
161    if (create_ssl_connection(&ctx, &bio, host, port, user, pass, secure) != 0) {
162        return 1;
163    }
164
165    /* Need at least two more arguments: get/set and a property name. */
166    if (optind + 1 >= argc) {
167        return usage();
168    } else {
169        const char* property = argv[optind+1];
170        if (strcmp(argv[optind], "get") == 0) {
171            result = ioctl_get(bio, property);
172        } else if (strcmp(argv[optind], "set") == 0) {
173            const char* value = (optind + 2 >= argc) ? argv[optind+2] : NULL;
174            result = ioctl_set(bio, property, value);
175        }
176    }
177
178    BIO_free_all(bio);
179    if (secure) {
180        SSL_CTX_free(ctx);
181    }
182
183    return result;
184}
185