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