1 /*
2 * Copyright (c) 1998,1999,2000
3 * Traakan, Inc., Los Altos, CA
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
11 * disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * Project: NDMJOB
31 * Ident: $Id: $
32 *
33 * Description:
34 *
35 */
36
37 #include "ndmos.h"
38 #include "wraplib.h"
39
40
wrap_main(int ac,char * av[],struct wrap_ccb * wccb)41 int wrap_main(int ac, char* av[], struct wrap_ccb* wccb)
42 {
43 int rc;
44
45 rc = wrap_process_args(ac, av, wccb);
46 if (rc) return rc;
47
48 rc = wrap_main_start_index_file(wccb);
49 if (rc) return rc;
50
51 rc = wrap_main_start_image_file(wccb);
52 if (rc) return rc;
53
54
55 return 0;
56 }
57
wrap_main_start_index_file(struct wrap_ccb * wccb)58 int wrap_main_start_index_file(struct wrap_ccb* wccb)
59 {
60 char* filename = wccb->I_index_file_name;
61 FILE* fp;
62
63 if (!filename) return 0;
64
65 if (filename[0] == '#') {
66 int fd = atoi(filename + 1);
67
68 if (fd < 2 || fd > 100) {
69 /* huey! */
70 strcpy(wccb->errmsg, "bad -I#N");
71 return -1;
72 }
73 fp = fdopen(fd, "w");
74 if (!fp) {
75 sprintf(wccb->errmsg, "failed fdopen %s", filename);
76 return -1;
77 }
78 } else {
79 fp = fopen(filename, "w");
80 if (!fp) {
81 sprintf(wccb->errmsg, "failed open %s", filename);
82 return -1;
83 }
84 }
85
86 wccb->index_fp = fp;
87
88 return 0;
89 }
90
wrap_main_start_image_file(struct wrap_ccb * wccb)91 int wrap_main_start_image_file(struct wrap_ccb* wccb)
92 {
93 char* filename = wccb->f_file_name;
94 int fd, o_mode;
95
96 switch (wccb->op) {
97 case WRAP_CCB_OP_BACKUP:
98 o_mode = O_CREAT | O_WRONLY;
99 break;
100
101 case WRAP_CCB_OP_RECOVER:
102 case WRAP_CCB_OP_RECOVER_FILEHIST:
103 o_mode = O_RDONLY;
104 break;
105
106 default:
107 abort();
108 return -1;
109 }
110
111 if (!filename) filename = "-";
112
113 if (strcmp(filename, "-") == 0) {
114 if (wccb->op == WRAP_CCB_OP_BACKUP) {
115 fd = 1;
116 } else {
117 fd = 0;
118 }
119 } else if (filename[0] == '#') {
120 fd = atoi(filename + 1);
121
122 if (fd < 2 || fd > 100) {
123 /* huey! */
124 strcpy(wccb->errmsg, "bad -f#N");
125 return -1;
126 }
127 } else {
128 fd = open(filename, o_mode, 0666);
129 if (fd < 0) {
130 sprintf(wccb->errmsg, "failed open %s", filename);
131 return -1;
132 }
133 }
134
135 wccb->data_conn_fd = fd;
136
137 return 0;
138 }
139
wrap_log(struct wrap_ccb * wccb,char * fmt,...)140 void wrap_log(struct wrap_ccb* wccb, char* fmt, ...)
141 {
142 va_list ap;
143 char buf[4096];
144
145 if (!wccb->index_fp && wccb->d_debug < 1) return;
146
147 sprintf(buf, "%04d ", ++wccb->log_seq_num);
148
149 va_start(ap, fmt);
150 vsnprintf(buf + 5, sizeof(buf) - 5, fmt, ap);
151 va_end(ap);
152
153 if (wccb->index_fp) wrap_send_log_message(wccb->index_fp, buf);
154
155 if (wccb->d_debug > 0) fprintf(stderr, "LOG: %s\n", buf);
156 }
157
wrap_set_error(struct wrap_ccb * wccb,int error)158 int wrap_set_error(struct wrap_ccb* wccb, int error)
159 {
160 if (error == 0) error = -3;
161
162 wccb->error = error;
163
164 return wccb->error;
165 }
166
wrap_set_errno(struct wrap_ccb * wccb)167 int wrap_set_errno(struct wrap_ccb* wccb)
168 {
169 return wrap_set_error(wccb, errno);
170 }
171
172
173 /*
174 * wrap -c [-B TYPE] [-d N] [-I FILE] [-E NAME=VALUE ...]
175 * wrap -x [-B TYPE] [-d N] [-I FILE] [-E NAME=VALUE ...]
176 * ORIGINAL_NAME @pos NEW_NAME ...
177 * wrap -t [-B TYPE] [-d N] [-I FILE] [-E NAME=VALUE ...]
178 * ORIGINAL_NAME @pos
179 */
180
wrap_process_args(int argc,char * argv[],struct wrap_ccb * wccb)181 int wrap_process_args(int argc, char* argv[], struct wrap_ccb* wccb)
182 {
183 int c;
184 enum wrap_ccb_op op;
185 char* p;
186
187 NDMOS_MACRO_ZEROFILL(wccb);
188
189 wccb->progname = argv[0];
190
191 if (argc < 2) {
192 strcpy(wccb->errmsg, "too few arguments");
193 return -1;
194 }
195
196 while ((c = getopt(argc, argv, "cxtB:d:I:E:f:o:")) != EOF) {
197 switch (c) {
198 case 'c':
199 op = WRAP_CCB_OP_BACKUP;
200 goto set_op;
201
202 case 't':
203 op = WRAP_CCB_OP_RECOVER_FILEHIST;
204 goto set_op;
205
206 case 'x':
207 op = WRAP_CCB_OP_RECOVER;
208 goto set_op;
209
210 set_op:
211 if (wccb->op != WRAP_CCB_OP_NONE) {
212 strcpy(wccb->errmsg, "only one of -c, -x, -t");
213 return -1;
214 }
215 wccb->op = op;
216 break;
217
218 case 'B':
219 if (wccb->B_butype) {
220 strcpy(wccb->errmsg, "only one -B allowed");
221 return -1;
222 }
223 wccb->B_butype = optarg;
224 break;
225
226 case 'd':
227 wccb->d_debug = atoi(optarg);
228 break;
229
230 case 'E':
231 if (wccb->n_env >= WRAP_MAX_ENV) {
232 strcpy(wccb->errmsg, "-E overflow");
233 return -1;
234 }
235 p = strchr(optarg, '=');
236 if (p) {
237 *p++ = 0;
238 } else {
239 p = "";
240 }
241 wccb->env[wccb->n_env].name = optarg;
242 wccb->env[wccb->n_env].value = p;
243 wccb->n_env++;
244 break;
245
246 case 'f':
247 if (wccb->f_file_name) {
248 strcpy(wccb->errmsg, "only one -f allowed");
249 return -1;
250 }
251 wccb->f_file_name = optarg;
252 break;
253
254 case 'I':
255 if (wccb->I_index_file_name) {
256 strcpy(wccb->errmsg, "only one -I allowed");
257 return -1;
258 }
259 wccb->I_index_file_name = optarg;
260 break;
261
262 case 'o':
263 if (wccb->n_o_option >= WRAP_MAX_O_OPTION) {
264 strcpy(wccb->errmsg, "-o overflow");
265 return -1;
266 }
267 wccb->o_option[wccb->n_o_option] = optarg;
268 wccb->n_o_option++;
269 break;
270
271 default:
272 strcpy(wccb->errmsg, "unknown option");
273 return -1;
274 }
275 }
276
277 switch (wccb->op) {
278 default:
279 abort(); /* just can't happen */
280
281 case WRAP_CCB_OP_NONE:
282 strcpy(wccb->errmsg, "one of -c, -x, or -t required");
283 return -1;
284
285 case WRAP_CCB_OP_BACKUP:
286 if (optind < argc) {
287 strcpy(wccb->errmsg, "extra args not allowed for -c");
288 return -1;
289 }
290 break;
291
292 case WRAP_CCB_OP_RECOVER:
293 case WRAP_CCB_OP_RECOVER_FILEHIST:
294 break;
295 }
296
297 for (c = optind; c + 2 < argc; c += 3) {
298 p = argv[c + 1];
299
300 if (p[0] != '@') {
301 sprintf(wccb->errmsg, "malformed fhinfo %s", p);
302 return -1;
303 }
304
305 if (wccb->n_file >= WRAP_MAX_FILE) {
306 strcpy(wccb->errmsg, "file table overflow");
307 return -1;
308 }
309
310 if (strcmp(p, "@-") == 0) {
311 wccb->file[wccb->n_file].fhinfo = WRAP_INVALID_FHINFO;
312 } else {
313 wccb->file[wccb->n_file].fhinfo = NDMOS_API_STRTOLL(p + 1, &p, 0);
314 if (*p != 0) {
315 sprintf(wccb->errmsg, "malformed fhinfo %s", p);
316 return -1;
317 }
318 }
319
320 wccb->file[wccb->n_file].original_name = argv[c];
321 wccb->file[wccb->n_file].save_to_name = argv[c + 2];
322
323 wccb->n_file++;
324 }
325
326 if (c < argc) {
327 strcpy(wccb->errmsg, "superfluous args at end");
328 return -1;
329 }
330
331 p = wrap_find_env(wccb, "HIST");
332 if (p) {
333 switch (*p) {
334 case 'y':
335 case 'Y':
336 p = wrap_find_env(wccb, "HIST_TYPE");
337 if (!p) { p = "y"; }
338 break;
339 }
340
341 switch (*p) {
342 case 'y':
343 case 'Y':
344 wccb->hist_enable = 'y';
345 break;
346
347 case 'd':
348 case 'D':
349 wccb->hist_enable = 'd';
350 break;
351
352 case 'f':
353 case 'F':
354 wccb->hist_enable = 'f';
355 break;
356
357 default:
358 /* gripe? */
359 break;
360 }
361 }
362
363 p = wrap_find_env(wccb, "DIRECT");
364 if (p) {
365 if (*p == 'y') { wccb->direct_enable = 1; }
366 }
367
368 p = wrap_find_env(wccb, "FILESYSTEM");
369 if (!p) p = wrap_find_env(wccb, "PREFIX");
370 if (!p) p = "/";
371
372 wccb->backup_root = p;
373
374 return 0;
375 }
376
wrap_find_env(struct wrap_ccb * wccb,char * name)377 char* wrap_find_env(struct wrap_ccb* wccb, char* name)
378 {
379 int i;
380
381 for (i = 0; i < wccb->n_env; i++) {
382 if (strcmp(wccb->env[i].name, name) == 0) return wccb->env[i].value;
383 }
384
385 return 0;
386 }
387
388
wrap_cmd_add_with_escapes(char * cmd,char * word,char * special)389 int wrap_cmd_add_with_escapes(char* cmd, char* word, char* special)
390 {
391 char* cmd_lim = &cmd[WRAP_MAX_COMMAND - 3];
392 char* p;
393 int c;
394
395 p = cmd;
396 while (*p) p++;
397 if (p != cmd) *p++ = ' ';
398
399 while ((c = *word++) != 0) {
400 if (p >= cmd_lim) return -1; /* overflow */
401 if (c == '\\' || strchr(special, c)) *p++ = '\\';
402 *p++ = c;
403 }
404 *p = 0;
405
406 return 0;
407 }
408
wrap_cmd_add_with_sh_escapes(char * cmd,char * word)409 int wrap_cmd_add_with_sh_escapes(char* cmd, char* word)
410 {
411 return wrap_cmd_add_with_escapes(cmd, word, " \t`'\"*?[]$");
412 }
413
wrap_cmd_add_allow_file_wildcards(char * cmd,char * word)414 int wrap_cmd_add_allow_file_wildcards(char* cmd, char* word)
415 {
416 return wrap_cmd_add_with_escapes(cmd, word, " \t`'\"$");
417 }
418
419
wrap_pipe_fork_exec(char * cmd,int fdmap[3])420 int wrap_pipe_fork_exec(char* cmd, int fdmap[3])
421 {
422 int pipes[3][2];
423 int child_fdmap[3];
424 int nullfd = -1;
425 int i;
426 int rc = -1;
427
428 for (i = 0; i < 3; i++) {
429 pipes[i][0] = -1;
430 pipes[i][1] = -1;
431 child_fdmap[i] = -1;
432 }
433
434 for (i = 0; i < 3; i++) {
435 if (fdmap[i] >= 0) {
436 child_fdmap[i] = fdmap[i];
437 continue;
438 }
439 switch (fdmap[i]) {
440 case WRAP_FDMAP_DEV_NULL:
441 if (nullfd < 0) {
442 nullfd = open("/dev/null", 2);
443 if (nullfd < 0) { goto bail_out; }
444 }
445 child_fdmap[i] = nullfd;
446 break;
447
448 case WRAP_FDMAP_INPUT_PIPE:
449 rc = pipe(pipes[i]);
450 if (rc != 0) { goto bail_out; }
451 child_fdmap[i] = pipes[i][0];
452 break;
453
454 case WRAP_FDMAP_OUTPUT_PIPE:
455 rc = pipe(pipes[i]);
456 if (rc != 0) { goto bail_out; }
457 child_fdmap[i] = pipes[i][1];
458 break;
459
460 default:
461 goto bail_out;
462 }
463 }
464
465 rc = fork();
466 if (rc < 0) { goto bail_out; }
467
468 if (rc == 0) {
469 /* child */
470 dup2(child_fdmap[2], 2);
471 dup2(child_fdmap[1], 1);
472 dup2(child_fdmap[0], 0);
473
474 for (rc = 3; rc < 100; rc++) close(rc);
475
476 execl("/bin/sh", "sh", "-c", cmd, NULL);
477
478 fprintf(stderr, "EXEC FAILED %s\n", cmd);
479 exit(127);
480 }
481
482 if (nullfd >= 0) close(nullfd);
483
484 for (i = 0; i < 3; i++) {
485 if (fdmap[i] >= 0) { continue; }
486 switch (fdmap[i]) {
487 case WRAP_FDMAP_DEV_NULL:
488 break;
489
490 case WRAP_FDMAP_INPUT_PIPE:
491 close(pipes[i][0]);
492 fdmap[i] = pipes[i][1];
493 break;
494
495 case WRAP_FDMAP_OUTPUT_PIPE:
496 close(pipes[i][1]);
497 fdmap[i] = pipes[i][0];
498 break;
499
500 default:
501 abort();
502 }
503 }
504
505 return rc; /* PID */
506
507 bail_out:
508 if (nullfd >= 0) close(nullfd);
509
510 for (i = 0; i < 3; i++) {
511 if (pipes[i][0] >= 0) close(pipes[i][0]);
512 if (pipes[i][1] >= 0) close(pipes[i][1]);
513 }
514
515 return -1;
516 }
517
518
wrap_parse_msg(char * buf,struct wrap_msg_buf * wmsg)519 int wrap_parse_msg(char* buf, struct wrap_msg_buf* wmsg)
520 {
521 int c1, c2;
522
523 c1 = buf[0];
524 c2 = buf[1];
525
526 if (buf[2] != ' ') { return -1; }
527
528 if (c1 == 'L' && c2 == 'x') { /* log_message */
529 return wrap_parse_log_message_msg(buf, wmsg);
530 }
531
532 if (c1 == 'H' && c2 == 'F') { /* add_file */
533 return wrap_parse_add_file_msg(buf, wmsg);
534 }
535
536 if (c1 == 'H' && c2 == 'D') { /* add_dirent */
537 return wrap_parse_add_dirent_msg(buf, wmsg);
538 }
539
540 if (c1 == 'H' && c2 == 'N') { /* add_node */
541 return wrap_parse_add_node_msg(buf, wmsg);
542 }
543
544 if (c1 == 'D' && c2 == 'E') { /* add_env */
545 return wrap_parse_add_env_msg(buf, wmsg);
546 }
547
548 if (c1 == 'D' && c2 == 'R') { /* data_read */
549 return wrap_parse_data_read_msg(buf, wmsg);
550 }
551
552 return -1;
553 }
554
wrap_parse_log_message_msg(char * buf,struct wrap_msg_buf * wmsg)555 int wrap_parse_log_message_msg(char* buf, struct wrap_msg_buf* wmsg)
556 {
557 struct wrap_log_message* res = &wmsg->body.log_message;
558 char* scan = buf + 3;
559 int rc;
560
561 wmsg->msg_type = WRAP_MSGTYPE_LOG_MESSAGE;
562
563 while (*scan && *scan == ' ') scan++;
564
565 rc = wrap_cstr_to_str(scan, res->message, sizeof res->message);
566 if (rc < 0) return -2;
567
568 return 0;
569 }
570
wrap_send_log_message(FILE * fp,char * message)571 int wrap_send_log_message(FILE* fp, char* message)
572 {
573 struct wrap_msg_buf wmsg;
574 struct wrap_log_message* res = &wmsg.body.log_message;
575
576 if (!fp) return -1;
577
578 wrap_cstr_from_str(message, res->message, sizeof res->message);
579 fprintf(fp, "Lx %s\n", res->message);
580
581 return 0;
582 }
583
wrap_parse_add_file_msg(char * buf,struct wrap_msg_buf * wmsg)584 int wrap_parse_add_file_msg(char* buf, struct wrap_msg_buf* wmsg)
585 {
586 struct wrap_add_file* res = &wmsg->body.add_file;
587 char* scan = buf + 3;
588 char* p;
589 int rc;
590
591 wmsg->msg_type = WRAP_MSGTYPE_ADD_FILE;
592
593 res->fstat.valid = 0;
594 res->fhinfo = WRAP_INVALID_FHINFO;
595
596 while (*scan && *scan == ' ') scan++;
597 if (*scan == 0) return -1;
598
599 p = scan;
600 while (*scan && *scan != ' ') scan++;
601
602 if (*scan) {
603 *scan = 0;
604 rc = wrap_cstr_to_str(p, res->path, sizeof res->path);
605 *scan++ = ' ';
606 } else {
607 rc = wrap_cstr_to_str(p, res->path, sizeof res->path);
608 }
609 if (rc < 0) return -2;
610
611 while (*scan) {
612 p = scan + 1;
613 switch (*scan) {
614 case ' ':
615 scan++;
616 continue;
617
618 case '@':
619 res->fhinfo = NDMOS_API_STRTOLL(p, &scan, 0);
620 break;
621
622 default:
623 rc = wrap_parse_fstat_subr(&scan, &res->fstat);
624 if (rc < 0) return rc;
625 break;
626 }
627
628 if (*scan != ' ' && *scan != 0) {
629 /* bogus */
630 return -1;
631 }
632 }
633
634 return 0;
635 }
636
wrap_send_add_file(FILE * fp,char * path,uint64_t fhinfo,struct wrap_fstat * fstat)637 int wrap_send_add_file(FILE* fp,
638 char* path,
639 uint64_t fhinfo,
640 struct wrap_fstat* fstat)
641 {
642 struct wrap_msg_buf wmsg;
643 struct wrap_add_file* res = &wmsg.body.add_file;
644
645 if (!fp) return -1;
646
647 wrap_cstr_from_str(path, res->path, sizeof res->path);
648 fprintf(fp, "HF %s", res->path);
649
650 if (fhinfo != WRAP_INVALID_FHINFO) fprintf(fp, " @%llu", fhinfo);
651
652 wrap_send_fstat_subr(fp, fstat);
653
654 fprintf(fp, "\n");
655
656 return 0;
657 }
658
wrap_parse_add_dirent_msg(char * buf,struct wrap_msg_buf * wmsg)659 int wrap_parse_add_dirent_msg(char* buf, struct wrap_msg_buf* wmsg)
660 {
661 struct wrap_add_dirent* res = &wmsg->body.add_dirent;
662 char* scan = buf + 3;
663 char* p;
664 int rc;
665
666 wmsg->msg_type = WRAP_MSGTYPE_ADD_DIRENT;
667
668 res->fhinfo = WRAP_INVALID_FHINFO;
669
670 while (*scan && *scan == ' ') scan++;
671 if (*scan == 0) return -1;
672
673 res->dir_fileno = NDMOS_API_STRTOLL(scan, &scan, 0);
674 if (*scan != ' ') return -1;
675
676 while (*scan == ' ') scan++;
677
678 if (*scan == 0) return -1;
679
680 p = scan;
681 while (*scan && *scan != ' ') scan++;
682
683 if (*scan) {
684 *scan = 0;
685 rc = wrap_cstr_to_str(p, res->name, sizeof res->name);
686 *scan++ = ' ';
687 } else {
688 rc = wrap_cstr_to_str(p, res->name, sizeof res->name);
689 }
690 if (rc < 0) return -2;
691
692 res->fileno = NDMOS_API_STRTOLL(scan, &scan, 0);
693 if (*scan != ' ' && *scan != 0) return -1;
694
695 while (*scan == ' ') scan++;
696
697 if (*scan == '@') { res->fhinfo = NDMOS_API_STRTOLL(scan + 1, &scan, 0); }
698
699 if (*scan != ' ' && *scan != 0) return -1;
700
701 while (*scan == ' ') scan++;
702
703 if (*scan) return -1;
704
705 return 0;
706 }
707
wrap_send_add_dirent(FILE * fp,char * name,uint64_t fhinfo,uint64_t dir_fileno,uint64_t fileno)708 int wrap_send_add_dirent(FILE* fp,
709 char* name,
710 uint64_t fhinfo,
711 uint64_t dir_fileno,
712 uint64_t fileno)
713 {
714 struct wrap_msg_buf wmsg;
715 struct wrap_add_dirent* res = &wmsg.body.add_dirent;
716
717 if (!fp) return -1;
718
719 wrap_cstr_from_str(name, res->name, sizeof res->name);
720 fprintf(fp, "HD %llu %s %llu", dir_fileno, res->name, fileno);
721
722 if (fhinfo != WRAP_INVALID_FHINFO) fprintf(fp, " @%llu", fhinfo);
723
724 fprintf(fp, "\n");
725
726 return 0;
727 }
728
729
wrap_parse_add_node_msg(char * buf,struct wrap_msg_buf * wmsg)730 int wrap_parse_add_node_msg(char* buf, struct wrap_msg_buf* wmsg)
731 {
732 struct wrap_add_node* res = &wmsg->body.add_node;
733 char* scan = buf + 3;
734 char* p;
735 int rc;
736
737 wmsg->msg_type = WRAP_MSGTYPE_ADD_NODE;
738
739 res->fstat.valid = 0;
740 res->fhinfo = WRAP_INVALID_FHINFO;
741
742 while (*scan && *scan == ' ') scan++;
743 if (*scan == 0) return -1;
744
745 res->fstat.fileno = NDMOS_API_STRTOLL(scan, &scan, 0);
746 if (*scan != ' ' && *scan != 0) return -1;
747
748 res->fstat.valid |= WRAP_FSTAT_VALID_FILENO;
749
750 while (*scan) {
751 p = scan + 1;
752 switch (*scan) {
753 case ' ':
754 scan++;
755 continue;
756
757 case '@':
758 res->fhinfo = NDMOS_API_STRTOLL(p, &scan, 0);
759 break;
760
761 default:
762 rc = wrap_parse_fstat_subr(&scan, &res->fstat);
763 if (rc < 0) return rc;
764 break;
765 }
766
767 if (*scan != ' ' && *scan != 0) {
768 /* bogus */
769 return -1;
770 }
771 }
772
773 if ((res->fstat.valid & WRAP_FSTAT_VALID_FILENO) == 0) return -5;
774
775 return 0;
776 }
777
wrap_send_add_node(FILE * fp,uint64_t fhinfo,struct wrap_fstat * fstat)778 int wrap_send_add_node(FILE* fp, uint64_t fhinfo, struct wrap_fstat* fstat)
779 {
780 uint32_t save_valid;
781
782 if (!fp) return -1;
783
784 if (fstat->valid & WRAP_FSTAT_VALID_FILENO) {
785 fprintf(fp, "HN %llu", fstat->fileno);
786 } else {
787 fprintf(fp, "HN 0000000000");
788 }
789
790 if (fhinfo != WRAP_INVALID_FHINFO) fprintf(fp, " @%llu", fhinfo);
791
792 /* suppress iFILENO */
793 save_valid = fstat->valid;
794 fstat->valid &= ~WRAP_FSTAT_VALID_FILENO;
795 wrap_send_fstat_subr(fp, fstat);
796 fstat->valid = save_valid;
797
798 fprintf(fp, "\n");
799
800 return 0;
801 }
802
803
wrap_parse_fstat_subr(char ** scanp,struct wrap_fstat * fstat)804 int wrap_parse_fstat_subr(char** scanp, struct wrap_fstat* fstat)
805 {
806 char* scan = *scanp;
807 char* p = scan + 1;
808 uint32_t valid = 0;
809
810 valid = 0;
811 switch (*scan) {
812 case 's': /* size */
813 valid = WRAP_FSTAT_VALID_SIZE;
814 fstat->size = NDMOS_API_STRTOLL(p, &scan, 0);
815 break;
816
817 case 'i': /* fileno (inum) */
818 valid = WRAP_FSTAT_VALID_FILENO;
819 fstat->fileno = NDMOS_API_STRTOLL(p, &scan, 0);
820 break;
821
822 case 'm': /* mode low twelve bits */
823 valid = WRAP_FSTAT_VALID_MODE;
824 fstat->mode = strtol(p, &scan, 8);
825 break;
826
827 case 'l': /* link count */
828 valid = WRAP_FSTAT_VALID_LINKS;
829 fstat->links = strtol(p, &scan, 0);
830 break;
831
832 case 'u': /* uid */
833 valid = WRAP_FSTAT_VALID_UID;
834 fstat->uid = strtol(p, &scan, 0);
835 break;
836
837 case 'g': /* gid */
838 valid = WRAP_FSTAT_VALID_GID;
839 fstat->gid = strtol(p, &scan, 0);
840 break;
841
842 case 't': /* one of the times */
843 p = scan + 2;
844 switch (scan[1]) {
845 case 'm': /* mtime */
846 valid = WRAP_FSTAT_VALID_MTIME;
847 fstat->mtime = strtol(p, &scan, 0);
848 break;
849
850 case 'a': /* atime */
851 valid = WRAP_FSTAT_VALID_ATIME;
852 fstat->atime = strtol(p, &scan, 0);
853 break;
854
855 case 'c': /* ctime */
856 valid = WRAP_FSTAT_VALID_CTIME;
857 fstat->ctime = strtol(p, &scan, 0);
858 break;
859
860 default:
861 return -3;
862 }
863 break;
864
865 case 'f': /* ftype (file type) */
866 valid = WRAP_FSTAT_VALID_FTYPE;
867 switch (scan[1]) {
868 case 'd':
869 fstat->ftype = WRAP_FTYPE_DIR;
870 break;
871 case 'p':
872 fstat->ftype = WRAP_FTYPE_FIFO;
873 break;
874 case 'c':
875 fstat->ftype = WRAP_FTYPE_CSPEC;
876 break;
877 case 'b':
878 fstat->ftype = WRAP_FTYPE_BSPEC;
879 break;
880 case '-':
881 fstat->ftype = WRAP_FTYPE_REG;
882 break;
883 case 'l':
884 fstat->ftype = WRAP_FTYPE_SLINK;
885 break;
886 case 's':
887 fstat->ftype = WRAP_FTYPE_SOCK;
888 break;
889 case 'R':
890 fstat->ftype = WRAP_FTYPE_REGISTRY;
891 break;
892 case 'o':
893 fstat->ftype = WRAP_FTYPE_OTHER;
894 break;
895 default:
896 fstat->ftype = WRAP_FTYPE_INVALID;
897 return -5;
898 }
899 scan += 2;
900 break;
901
902 default:
903 return -3;
904 }
905
906 if (*scan != ' ' && *scan != 0) return -1;
907
908 fstat->valid |= valid;
909 *scanp = scan;
910
911 return 0;
912 }
913
wrap_send_fstat_subr(FILE * fp,struct wrap_fstat * fstat)914 int wrap_send_fstat_subr(FILE* fp, struct wrap_fstat* fstat)
915 {
916 if (!fp) return -1;
917
918 if (fstat->valid & WRAP_FSTAT_VALID_FTYPE) {
919 int c = 0;
920
921 switch (fstat->ftype) {
922 default:
923 case WRAP_FTYPE_INVALID:
924 c = 0;
925 break;
926 case WRAP_FTYPE_DIR:
927 c = 'd';
928 break;
929 case WRAP_FTYPE_FIFO:
930 c = 'p';
931 break;
932 case WRAP_FTYPE_CSPEC:
933 c = 'c';
934 break;
935 case WRAP_FTYPE_BSPEC:
936 c = 'b';
937 break;
938 case WRAP_FTYPE_REG:
939 c = '-';
940 break;
941 case WRAP_FTYPE_SLINK:
942 c = 'l';
943 break;
944 case WRAP_FTYPE_SOCK:
945 c = 's';
946 break;
947 case WRAP_FTYPE_REGISTRY:
948 c = 'R';
949 break;
950 case WRAP_FTYPE_OTHER:
951 c = 'o';
952 break;
953 }
954
955 if (c) {
956 fprintf(fp, " f%c", c);
957 } else {
958 return -1;
959 }
960 }
961
962 if (fstat->valid & WRAP_FSTAT_VALID_MODE) {
963 fprintf(fp, " m%04o", fstat->mode);
964 }
965
966 if (fstat->valid & WRAP_FSTAT_VALID_LINKS) {
967 fprintf(fp, " l%lu", fstat->links);
968 }
969
970 if (fstat->valid & WRAP_FSTAT_VALID_SIZE) {
971 fprintf(fp, " s%llu", fstat->size);
972 }
973
974 if (fstat->valid & WRAP_FSTAT_VALID_UID) { fprintf(fp, " u%lu", fstat->uid); }
975
976 if (fstat->valid & WRAP_FSTAT_VALID_GID) { fprintf(fp, " g%lu", fstat->gid); }
977
978 if (fstat->valid & WRAP_FSTAT_VALID_ATIME) {
979 fprintf(fp, " ta%lu", fstat->atime);
980 }
981
982 if (fstat->valid & WRAP_FSTAT_VALID_MTIME) {
983 fprintf(fp, " tm%lu", fstat->mtime);
984 }
985
986 if (fstat->valid & WRAP_FSTAT_VALID_CTIME) {
987 fprintf(fp, " tc%lu", fstat->ctime);
988 }
989
990 if (fstat->valid & WRAP_FSTAT_VALID_FILENO) {
991 fprintf(fp, " i%llu", fstat->fileno);
992 }
993
994 return 0;
995 }
996
wrap_parse_add_env_msg(char * buf,struct wrap_msg_buf * wmsg)997 int wrap_parse_add_env_msg(char* buf, struct wrap_msg_buf* wmsg)
998 {
999 struct wrap_add_env* res = &wmsg->body.add_env;
1000 char* scan = buf + 3;
1001 char* p;
1002 int rc;
1003
1004 wmsg->msg_type = WRAP_MSGTYPE_ADD_ENV;
1005
1006 while (*scan && *scan == ' ') scan++;
1007 if (*scan == 0) return -1;
1008
1009 p = scan;
1010 while (*scan && *scan != ' ') scan++;
1011
1012 if (*scan) {
1013 *scan = 0;
1014 rc = wrap_cstr_to_str(p, res->name, sizeof res->name);
1015 *scan++ = ' ';
1016 } else {
1017 rc = wrap_cstr_to_str(p, res->name, sizeof res->name);
1018 }
1019 if (rc < 0) return -2;
1020
1021 while (*scan && *scan == ' ') scan++;
1022
1023 p = scan;
1024 while (*scan && *scan != ' ') scan++;
1025
1026 if (*scan) {
1027 *scan = 0;
1028 rc = wrap_cstr_to_str(p, res->value, sizeof res->value);
1029 *scan++ = ' ';
1030 } else {
1031 rc = wrap_cstr_to_str(p, res->value, sizeof res->value);
1032 }
1033 if (rc < 0) return -2;
1034
1035 return 0;
1036 }
1037
wrap_send_add_env(FILE * fp,char * name,char * value)1038 int wrap_send_add_env(FILE* fp, char* name, char* value)
1039 {
1040 struct wrap_msg_buf wmsg;
1041 struct wrap_add_env* res = &wmsg.body.add_env;
1042
1043 if (!fp) return -1;
1044
1045 wrap_cstr_from_str(name, res->name, sizeof res->name);
1046 wrap_cstr_from_str(value, res->value, sizeof res->value);
1047
1048 fprintf(fp, "DE %s %s\n", res->name, res->value);
1049
1050 return 0;
1051 }
1052
wrap_parse_data_read_msg(char * buf,struct wrap_msg_buf * wmsg)1053 int wrap_parse_data_read_msg(char* buf, struct wrap_msg_buf* wmsg)
1054 {
1055 struct wrap_data_read* res = &wmsg->body.data_read;
1056 char* scan = buf + 3;
1057
1058 wmsg->msg_type = WRAP_MSGTYPE_DATA_READ;
1059
1060 while (*scan && *scan == ' ') scan++;
1061 if (*scan == 0) return -1;
1062
1063 res->offset = NDMOS_API_STRTOLL(scan, &scan, 0);
1064 if (*scan != ' ') return -1;
1065
1066 while (*scan && *scan != ' ') scan++;
1067
1068 if (*scan == 0) return -1;
1069
1070 res->length = NDMOS_API_STRTOLL(scan, &scan, 0);
1071
1072 /* tolerate trailing white */
1073 while (*scan && *scan != ' ') scan++;
1074
1075 if (*scan != 0) return -1;
1076
1077 return 0;
1078 }
1079
wrap_send_data_read(FILE * fp,uint64_t offset,uint64_t length)1080 int wrap_send_data_read(FILE* fp, uint64_t offset, uint64_t length)
1081 {
1082 if (!fp) return -1;
1083
1084 fprintf(fp, "DR %lld %lld\n", (int64_t)offset, (int64_t)length);
1085 fflush(fp);
1086
1087 return 0;
1088 }
1089
wrap_parse_data_stats_msg(char * buf,struct wrap_msg_buf * wmsg)1090 int wrap_parse_data_stats_msg(char* buf, struct wrap_msg_buf* wmsg)
1091 {
1092 return -1;
1093 }
1094
wrap_send_data_stats(FILE * fp)1095 int wrap_send_data_stats(FILE* fp)
1096 {
1097 if (!fp) return -1;
1098
1099 fprintf(fp, "DS ...\n");
1100 fflush(fp);
1101
1102 return 0;
1103 }
1104
1105
1106 /*
1107 * Recovery helpers
1108 ****************************************************************
1109 */
1110
wrap_reco_align_to_wanted(struct wrap_ccb * wccb)1111 int wrap_reco_align_to_wanted(struct wrap_ccb* wccb)
1112 {
1113 uint64_t distance;
1114 uint64_t unwanted_length;
1115
1116 top:
1117 /*
1118 * If there is an error, we're toast.
1119 */
1120 if (wccb->error) return wccb->error;
1121
1122 /*
1123 * If we're aligned, we're done.
1124 */
1125 if (wccb->expect_offset == wccb->want_offset) {
1126 if (wccb->expect_length < wccb->want_length && wccb->reading_length == 0) {
1127 wrap_reco_issue_read(wccb);
1128 }
1129 return wccb->error;
1130 }
1131
1132 /*
1133 * If we have a portion we don't want, consume it now
1134 */
1135 if (wccb->have_length > 0) {
1136 if (wccb->have_offset < wccb->want_offset) {
1137 distance = wccb->want_offset - wccb->have_offset;
1138 if (distance < wccb->have_length) {
1139 /*
1140 * We have some of what we want.
1141 * Consume (discard) unwanted part.
1142 */
1143 unwanted_length = distance;
1144 } else {
1145 unwanted_length = wccb->have_length;
1146 }
1147 } else {
1148 unwanted_length = wccb->have_length;
1149 }
1150 wrap_reco_consume(wccb, unwanted_length);
1151 goto top;
1152 }
1153
1154 if (wccb->expect_length > 0) {
1155 /* Incoming, but we don't have it yet. */
1156 wrap_reco_receive(wccb);
1157 goto top;
1158 }
1159
1160 /*
1161 * We don't have anything. We don't expect anything.
1162 * Time to issue an NDMP_DATA_NOTIFY_READ via this wrapper.
1163 */
1164
1165 wrap_reco_issue_read(wccb);
1166
1167 goto top;
1168 }
1169
wrap_reco_receive(struct wrap_ccb * wccb)1170 int wrap_reco_receive(struct wrap_ccb* wccb)
1171 {
1172 char* iobuf_end = &wccb->iobuf[wccb->n_iobuf];
1173 char* have_end = wccb->have + wccb->have_length;
1174 unsigned n_read = iobuf_end - have_end;
1175 int rc;
1176
1177 if (wccb->error) return wccb->error;
1178
1179 if (wccb->have_length == 0) {
1180 wccb->have = wccb->iobuf;
1181 have_end = wccb->have + wccb->have_length;
1182 }
1183
1184 if (n_read < 512 && wccb->have != wccb->iobuf) {
1185 /* Not much room at have_end. Front of iobuf available. */
1186 /* Compress */
1187 NDMOS_API_BCOPY(wccb->have, wccb->iobuf, wccb->have_length);
1188 wccb->have = wccb->iobuf;
1189 have_end = wccb->have + wccb->have_length;
1190 n_read = iobuf_end - have_end;
1191 }
1192
1193 if (n_read > wccb->reading_length) n_read = wccb->reading_length;
1194
1195 if (n_read == 0) {
1196 /* Hmmm. */
1197 abort();
1198 return -1;
1199 }
1200
1201 rc = read(wccb->data_conn_fd, have_end, n_read);
1202 if (rc > 0) {
1203 wccb->have_length += rc;
1204 wccb->reading_offset += rc;
1205 wccb->reading_length -= rc;
1206 } else {
1207 /* EOF or error */
1208 if (rc == 0) {
1209 strcpy(wccb->errmsg, "EOF on data connection");
1210 wrap_set_error(wccb, -1);
1211 } else {
1212 sprintf(wccb->errmsg, "errno %d on data connection", errno);
1213 wrap_set_errno(wccb);
1214 }
1215 }
1216
1217 return wccb->error;
1218 }
1219
wrap_reco_consume(struct wrap_ccb * wccb,uint32_t length)1220 int wrap_reco_consume(struct wrap_ccb* wccb, uint32_t length)
1221 {
1222 assert(wccb->have_length >= length);
1223
1224 wccb->have_offset += length;
1225 wccb->have_length -= length;
1226 wccb->expect_offset += length;
1227 wccb->expect_length -= length;
1228 wccb->have += length;
1229
1230 if (wccb->expect_length == 0) {
1231 assert(wccb->have_length == 0);
1232 wccb->expect_offset = -1ull;
1233 }
1234
1235 return wccb->error;
1236 }
1237
wrap_reco_must_have(struct wrap_ccb * wccb,uint32_t length)1238 int wrap_reco_must_have(struct wrap_ccb* wccb, uint32_t length)
1239 {
1240 if (wccb->want_length < length) wccb->want_length = length;
1241
1242 wrap_reco_align_to_wanted(wccb);
1243
1244 while (wccb->have_length < length && !wccb->error) {
1245 wrap_reco_align_to_wanted(wccb); /* triggers issue_read() */
1246 wrap_reco_receive(wccb);
1247 }
1248
1249 if (wccb->have_length >= length) return 0;
1250
1251 return wccb->error;
1252 }
1253
wrap_reco_seek(struct wrap_ccb * wccb,uint64_t want_offset,uint64_t want_length,uint32_t must_have_length)1254 int wrap_reco_seek(struct wrap_ccb* wccb,
1255 uint64_t want_offset,
1256 uint64_t want_length,
1257 uint32_t must_have_length)
1258 {
1259 if (wccb->error) return wccb->error;
1260
1261 wccb->want_offset = want_offset;
1262 wccb->want_length = want_length;
1263
1264 return wrap_reco_must_have(wccb, must_have_length);
1265 }
1266
wrap_reco_pass(struct wrap_ccb * wccb,int write_fd,uint64_t length,unsigned write_bsize)1267 int wrap_reco_pass(struct wrap_ccb* wccb,
1268 int write_fd,
1269 uint64_t length,
1270 unsigned write_bsize)
1271 {
1272 unsigned cnt;
1273 int rc;
1274
1275 while (length > 0) {
1276 if (wccb->error) break;
1277
1278 cnt = write_bsize;
1279 if (cnt > length) cnt = length;
1280
1281 if (wccb->have_length < cnt) { wrap_reco_must_have(wccb, cnt); }
1282
1283 rc = write(write_fd, wccb->have, cnt);
1284
1285 length -= cnt;
1286 wrap_reco_consume(wccb, cnt);
1287 }
1288
1289 return wccb->error;
1290 }
1291
wrap_reco_issue_read(struct wrap_ccb * wccb)1292 int wrap_reco_issue_read(struct wrap_ccb* wccb)
1293 {
1294 uint64_t off;
1295 uint64_t len;
1296
1297 assert(wccb->reading_length == 0);
1298
1299 if (wccb->data_conn_mode == 0) {
1300 struct stat st;
1301 int rc;
1302
1303 rc = fstat(wccb->data_conn_fd, &st);
1304 if (rc != 0) {
1305 sprintf(wccb->errmsg, "Can't fstat() data conn rc=%d", rc);
1306 return wrap_set_errno(wccb);
1307 }
1308 if (S_ISFIFO(st.st_mode)) {
1309 wccb->data_conn_mode = 'p';
1310 if (!wccb->index_fp) {
1311 strcpy(wccb->errmsg, "data_conn is pipe but no -I");
1312 return wrap_set_error(wccb, -3);
1313 }
1314 } else if (S_ISREG(st.st_mode)) {
1315 wccb->data_conn_mode = 'f';
1316 } else {
1317 sprintf(wccb->errmsg, "Unsupported data_conn type %o", st.st_mode);
1318 return wrap_set_error(wccb, -3);
1319 }
1320 }
1321
1322 off = wccb->want_offset;
1323 len = wccb->want_length;
1324
1325 off += wccb->have_length;
1326 len -= wccb->have_length;
1327
1328 if (len == 0) { abort(); }
1329
1330 wccb->last_read_offset = off;
1331 wccb->last_read_length = len;
1332
1333 switch (wccb->data_conn_mode) {
1334 default:
1335 abort();
1336 return -1;
1337
1338 case 'f':
1339 if (lseek(wccb->data_conn_fd, off, 0) < 0) { return -1; }
1340 break;
1341
1342 case 'p':
1343 wrap_send_data_read(wccb->index_fp, off, len);
1344 break;
1345 }
1346
1347 wccb->reading_offset = wccb->last_read_offset;
1348 wccb->reading_length = wccb->last_read_length;
1349
1350 if (wccb->have_length == 0) {
1351 wccb->expect_offset = wccb->reading_offset;
1352 wccb->expect_length = wccb->reading_length;
1353 } else {
1354 wccb->expect_length += len;
1355 }
1356
1357 return wccb->error;
1358 }
1359
1360
1361 /*
1362 * (Note: this is hoisted from ndml_cstr.c)
1363 *
1364 * Description:
1365 * Convert strings to/from a canonical strings (CSTR).
1366 *
1367 * The main reason for this is to eliminate spaces
1368 * in strings thus making multiple strings easily
1369 * delimited by white space.
1370 *
1371 * Canonical strings use the HTTP convention of
1372 * percent sign followed by two hex digits (%xx).
1373 * Characters outside the printable ASCII range,
1374 * space, and percent sign are so converted.
1375 *
1376 * Both interfaces return the length of the resulting
1377 * string, -1 if there is an overflow, or -2
1378 * there is a conversion error.
1379 */
1380
wrap_cstr_from_str(char * src,char * dst,unsigned dst_max)1381 int wrap_cstr_from_str(char* src, char* dst, unsigned dst_max)
1382 {
1383 static char cstr_to_hex[] = "0123456789ABCDEF";
1384 unsigned char* p = (unsigned char*)src;
1385 unsigned char* q = (unsigned char*)dst;
1386 unsigned char* q_end = q + dst_max - 1;
1387 int c;
1388
1389 while ((c = *p++) != 0) {
1390 if (c <= ' ' || c > 0x7E || c == NDMCSTR_WARN) {
1391 if (q + 3 > q_end) return -1;
1392 *q++ = NDMCSTR_WARN;
1393 *q++ = cstr_to_hex[(c >> 4) & 0xF];
1394 *q++ = cstr_to_hex[c & 0xF];
1395 } else {
1396 if (q + 1 > q_end) return -1;
1397 *q++ = c;
1398 }
1399 }
1400 *q = 0;
1401
1402 return q - (unsigned char*)dst;
1403 }
1404
wrap_cstr_to_str(char * src,char * dst,unsigned dst_max)1405 int wrap_cstr_to_str(char* src, char* dst, unsigned dst_max)
1406 {
1407 unsigned char* p = (unsigned char*)src;
1408 unsigned char* q = (unsigned char*)dst;
1409 unsigned char* q_end = q + dst_max - 1;
1410 int c, c1, c2;
1411
1412 while ((c = *p++) != 0) {
1413 if (q + 1 > q_end) return -1;
1414 if (c != NDMCSTR_WARN) {
1415 *q++ = c;
1416 continue;
1417 }
1418 c1 = wrap_cstr_from_hex(p[0]);
1419 c2 = wrap_cstr_from_hex(p[1]);
1420
1421 if (c1 < 0 || c2 < 0) {
1422 /* busted conversion */
1423 return -2;
1424 }
1425
1426 c = (c1 << 4) + c2;
1427 *q++ = c;
1428 p += 2;
1429 }
1430 *q = 0;
1431
1432 return q - (unsigned char*)dst;
1433 }
1434
wrap_cstr_from_hex(int c)1435 int wrap_cstr_from_hex(int c)
1436 {
1437 if ('0' <= c && c <= '9') return c - '0';
1438 if ('a' <= c && c <= 'f') return (c - 'a') + 10;
1439 if ('A' <= c && c <= 'F') return (c - 'A') + 10;
1440 return -1;
1441 }
1442