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