1 /*
2 * Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
3 * License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
4 */
5 #include "cmogstored.h"
6 #include "mgmt.h"
7 #include "iov_str.h"
8 #include "digest.h"
9
10 static char *
get_path(struct iovec * dst,struct mog_mgmt * mgmt,char * buf,bool sdup)11 get_path(struct iovec *dst, struct mog_mgmt *mgmt, char *buf, bool sdup)
12 {
13 dst->iov_base = buf + mgmt->mark[0];
14 dst->iov_len = mgmt->mark[1] - mgmt->mark[0];
15
16 if (mog_valid_path(dst->iov_base, dst->iov_len)) {
17 char *path;
18
19 if (sdup) {
20 path = malloc(dst->iov_len + 1);
21 if (!path) {
22 struct iovec iov;
23
24 IOV_STR(&iov, "ERROR: out-of-memory\r\n");
25 mog_mgmt_writev(mgmt, &iov, 1);
26
27 return NULL;
28 }
29
30 memcpy(path, dst->iov_base, dst->iov_len);
31 } else {
32 path = dst->iov_base;
33 }
34
35 path[dst->iov_len] = '\0';
36 return path;
37 } else {
38 struct iovec iov;
39
40 IOV_STR(&iov, "ERROR: uri invalid (contains ..)\r\n");
41 mog_mgmt_writev(mgmt, &iov, 1);
42 return NULL;
43 }
44 }
45
46 /* starts the MD5 request */
mog_mgmt_fn_digest(struct mog_fd * mfd,char * buf)47 void mog_mgmt_fn_digest(struct mog_fd *mfd, char *buf)
48 {
49 struct mog_mgmt *mgmt = &mfd->as.mgmt;
50 struct iovec iov[2];
51 char *path = get_path(iov, mgmt, buf, true);
52
53 if (!path) return;
54
55 TRACE(CMOGSTORED_MGMT_DIG_START(mfd->fd, mgmt->alg, path));
56
57 mgmt->forward = mog_file_open_read(mgmt->svc, path);
58 if (mgmt->forward) {
59 struct mog_file *file = &mgmt->forward->as.file;
60
61 mog_fadv_noreuse(mgmt->forward->fd, 0, 0 /* ALL */);
62 mog_fadv_sequential(mgmt->forward->fd, 0, 0 /* ALL */);
63 mog_digest_init(&file->digest, mgmt->alg);
64 file->pathlen = iov[0].iov_len;
65 file->path = path;
66 } else {
67 switch (mgmt->alg) {
68 case GC_MD5:
69 IOV_STR(&iov[1], " MD5=-1\r\n");
70 break;
71 case GC_SHA1:
72 IOV_STR(&iov[1], " SHA-1=-1\r\n");
73 break;
74 default: /* Ragel parser prevents this: */
75 die("BUG: unhandled algorithm: %d", mgmt->alg);
76 }
77 TRACE(CMOGSTORED_MGMT_DIG_DONE(mfd->fd, -1));
78 mog_mgmt_writev(mgmt, iov, 2);
79 free(path);
80 }
81 }
82
83 /* finishes the MD5 request */
84 #define CLEN(s) (sizeof(s)-1)
85
mog_mgmt_fn_digest_err(struct mog_fd * mfd)86 void mog_mgmt_fn_digest_err(struct mog_fd *mfd)
87 {
88 struct mog_mgmt *mgmt = &mfd->as.mgmt;
89 struct iovec iov[3];
90 struct mog_fd *file_mfd = mgmt->forward;
91 struct mog_file *file = &file_mfd->as.file;
92 long long offset = (long long)lseek(file_mfd->fd, 0, SEEK_CUR);
93 char buf[sizeof(" at 18446744073709551615 failed\r\n") - 1];
94
95 /* offset could be -1 here, but there ain't much we can do */
96
97 IOV_STR(iov, "ERR read ");
98 iov[1].iov_base = file->path;
99 iov[1].iov_len = file->pathlen;
100 iov[2].iov_base = buf;
101 iov[2].iov_len = snprintf(buf, sizeof(buf),
102 " at %lld failed\r\n", offset);
103 TRACE(CMOGSTORED_MGMT_DIG_DONE(mfd->fd, offset));
104 mog_mgmt_writev(mgmt, iov, 3);
105 }
106
107 /* output: "/$PATH MD5=hex\r\n" */
mog_mgmt_fn_digest_emit(struct mog_fd * mfd)108 void mog_mgmt_fn_digest_emit(struct mog_fd *mfd)
109 {
110 struct mog_mgmt *mgmt = &mfd->as.mgmt;
111 struct iovec iov[2];
112 char buf[CLEN(" SHA-1=") + 40 + CLEN("\r\n")];
113 char *b = buf;
114 struct mog_fd *file_mfd = mgmt->forward;
115 struct mog_file *file = &file_mfd->as.file;
116 size_t len;
117
118 iov[0].iov_base = file->path;
119 iov[0].iov_len = file->pathlen;
120
121 /* ugh, clean this up... */
122 switch (mgmt->alg) {
123 case GC_MD5:
124 b = mempcpy(b, " MD5=", CLEN(" MD5="));
125 len = 32;
126 iov[1].iov_len = CLEN(" MD5=") + 32 + CLEN("\r\n");
127 break;
128 case GC_SHA1:
129 b = mempcpy(b, " SHA-1=", CLEN(" SHA-1="));
130 len = 40;
131 iov[1].iov_len = sizeof(buf);
132 break;
133 default:
134 die("BUG: unhandled algorithm: %d", mgmt->alg);
135 }
136
137 mog_digest_hex(&file->digest, b, len);
138 b[len] = '\r';
139 b[len + 1] = '\n';
140 iov[1].iov_base = buf;
141 TRACE(CMOGSTORED_MGMT_DIG_DONE(mfd->fd, 0));
142 mog_mgmt_writev(mgmt, iov, 2);
143 }
144
145 /*
146 * writes to mgmt fd:
147 * "URI $SIZE\r\n" on success
148 * "URI -1\r\n" on failure
149 * "ERROR: uri invalid (contains ..)\r\n" on invalid paths
150 */
mog_mgmt_fn_size(struct mog_mgmt * mgmt,char * buf)151 void mog_mgmt_fn_size(struct mog_mgmt *mgmt, char *buf)
152 {
153 struct stat sb;
154 struct iovec iov[2];
155 char tmp[sizeof(" 18446744073709551615\r\n") - 1];
156 char *path = get_path(iov, mgmt, buf, false);
157
158 if (!path) return;
159
160 if (mog_stat(mgmt->svc, path, &sb) == 0) {
161 long long size = (long long)sb.st_size;
162
163 iov[1].iov_base = tmp;
164 iov[1].iov_len = snprintf(tmp, sizeof(tmp), " %lld\r\n", size);
165 } else {
166 IOV_STR(&iov[1], " -1\r\n");
167 }
168
169 mog_mgmt_writev(mgmt, iov, 2);
170 }
171
mog_mgmt_fn_blank(struct mog_mgmt * mgmt)172 void mog_mgmt_fn_blank(struct mog_mgmt *mgmt)
173 {
174 struct iovec iov;
175
176 IOV_STR(&iov, "\r\n");
177 mog_mgmt_writev(mgmt, &iov, 1);
178 }
179
mog_mgmt_fn_unknown(struct mog_mgmt * mgmt,char * buf)180 void mog_mgmt_fn_unknown(struct mog_mgmt *mgmt, char *buf)
181 {
182 struct iovec iov[3];
183
184 IOV_STR(&iov[0], "ERROR: unknown command: ");
185 iov[1].iov_base = mgmt->mark[0] + buf;
186 iov[1].iov_len = mgmt->mark[1] - mgmt->mark[0];
187 IOV_STR(&iov[2], "\r\n");
188 mog_mgmt_writev(mgmt, iov, 3);
189 }
190
mog_mgmt_fn_watch_err(struct mog_mgmt * mgmt)191 void mog_mgmt_fn_watch_err(struct mog_mgmt *mgmt)
192 {
193 struct iovec iov;
194
195 IOV_STR(&iov, "ERR iostat unavailable\r\n");
196 mog_mgmt_writev(mgmt, &iov, 1);
197 }
198
mog_mgmt_fn_aio_threads(struct mog_mgmt * mgmt,char * buf)199 void mog_mgmt_fn_aio_threads(struct mog_mgmt *mgmt, char *buf)
200 {
201 char *end;
202 unsigned long long nr;
203 char *nptr = buf + mgmt->mark[0];
204 char *eor = nptr + mgmt->mark[1] - mgmt->mark[0];
205
206 assert((*eor == '\n' || *eor == '\r') && "missing end-of-record");
207 *eor = 0;
208
209 nr = strtoull(nptr, &end, 10);
210 assert(*end == 0 && "ragel misfed mog_mgmt_fn_set_aio_threads");
211
212 if (nr > 0 && nr <= (size_t)INT_MAX)
213 mog_svc_aio_threads_enqueue(mgmt->svc, (unsigned)nr);
214
215 mog_mgmt_fn_blank(mgmt);
216 }
217