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 
38 #include "ndmagents.h"
39 #include "wraplib.h"
40 
41 #ifndef NDMOS_OPTION_NO_DATA_AGENT
42 
43 
44 /*
45  * Initialization and Cleanup
46  ****************************************************************
47  */
48 
49 /* Initialize -- Set data structure to know value, ignore current value */
ndmda_initialize(struct ndm_session * sess)50 int ndmda_initialize(struct ndm_session* sess)
51 {
52   sess->data_acb = NDMOS_API_MALLOC(sizeof(struct ndm_data_agent));
53   if (!sess->data_acb) return -1;
54   NDMOS_MACRO_ZEROFILL(sess->data_acb);
55 
56   sess->data_acb->data_state.state = NDMP9_DATA_STATE_IDLE;
57   ndmchan_initialize(&sess->data_acb->formatter_error, "dfp-error");
58   ndmchan_initialize(&sess->data_acb->formatter_wrap, "dfp-wrap");
59   ndmchan_initialize(&sess->data_acb->formatter_image, "dfp-image");
60   ndmda_fh_initialize(sess);
61 
62   return 0;
63 }
64 
65 /* Commission -- Get agent ready. Entire session has been initialize()d */
ndmda_commission(struct ndm_session * sess)66 int ndmda_commission(struct ndm_session* sess)
67 {
68   struct ndm_data_agent* da = sess->data_acb;
69 
70   da->data_state.state = NDMP9_DATA_STATE_IDLE;
71   ndmda_fh_commission(sess);
72 
73   return 0;
74 }
75 
76 /* Decommission -- Discard agent */
ndmda_decommission(struct ndm_session * sess)77 int ndmda_decommission(struct ndm_session* sess)
78 {
79   ndmis_data_close(sess);
80   ndmda_purge_environment(sess);
81   ndmda_purge_nlist(sess);
82   ndmda_fh_decommission(sess);
83   NDMOS_API_BZERO(sess->data_acb->bu_type, sizeof sess->data_acb->bu_type);
84 
85   ndmda_commission(sess);
86 
87   return 0;
88 }
89 
90 /* Destroy -- destroy agent */
ndmda_destroy(struct ndm_session * sess)91 int ndmda_destroy(struct ndm_session* sess)
92 {
93   if (!sess->data_acb) { return 0; }
94 
95   if (sess->data_acb->fmt_image_buf) {
96     NDMOS_API_FREE(sess->data_acb->fmt_image_buf);
97   }
98   if (sess->data_acb->fmt_error_buf) {
99     NDMOS_API_FREE(sess->data_acb->fmt_error_buf);
100   }
101   if (sess->data_acb->fmt_wrap_buf) {
102     NDMOS_API_FREE(sess->data_acb->fmt_wrap_buf);
103   }
104 
105   ndmda_fh_destroy(sess);
106 
107   NDMOS_API_FREE(sess->data_acb);
108   sess->data_acb = NULL;
109 
110   return 0;
111 }
112 
113 /* Belay -- Cancel partially issued activation/start */
ndmda_belay(struct ndm_session * sess)114 int ndmda_belay(struct ndm_session* sess)
115 {
116   ndmda_fh_belay(sess);
117   return ndmda_decommission(sess);
118 }
119 
120 
121 /*
122  * Semantic actions -- called from ndma_dispatch()
123  ****************************************************************
124  */
125 
add_env(struct ndm_env_table * envtab,char * cmd)126 static int add_env(struct ndm_env_table* envtab, char* cmd)
127 {
128   char buf[1024];
129   struct ndm_env_entry* entry;
130 
131   for (entry = envtab->head; entry; entry = entry->next) {
132     snprintf(buf, sizeof(buf) - 1, "%s=%s", entry->pval.name,
133              entry->pval.value);
134     buf[sizeof(buf) - 1] = '\0';
135     ndmda_add_to_cmd(cmd, "-E");
136     ndmda_add_to_cmd(cmd, buf);
137   }
138 
139   return 0;
140 }
141 
add_nlist(struct ndm_nlist_table * nlisttab,char * cmd)142 static int add_nlist(struct ndm_nlist_table* nlisttab, char* cmd)
143 {
144   char buf[32];
145   struct ndm_nlist_entry* entry;
146 
147   for (entry = nlisttab->head; entry; entry = entry->next) {
148     ndmda_add_to_cmd(cmd, entry->name.original_path);
149     if (entry->name.fh_info.valid == NDMP9_VALIDITY_VALID) {
150       snprintf(buf, sizeof(buf), "@%llu", entry->name.fh_info.value);
151       ndmda_add_to_cmd(cmd, buf);
152     } else {
153       ndmda_add_to_cmd(cmd, "@-");
154     }
155     ndmda_add_to_cmd(cmd, entry->name.destination_path);
156   }
157 
158   return 0;
159 }
160 
161 
ndmda_data_start_backup(struct ndm_session * sess)162 ndmp9_error ndmda_data_start_backup(struct ndm_session* sess)
163 {
164   struct ndm_data_agent* da = sess->data_acb;
165   ndmp9_error error = NDMP9_NO_ERR;
166   char cmd[NDMDA_MAX_CMD];
167 
168   strcpy(cmd, "wrap_");
169   strcat(cmd, da->bu_type);
170 
171   if (sess->param->log_level > 0) {
172     char tmpbuf[40];
173     snprintf(tmpbuf, sizeof(tmpbuf), "-d%d", sess->param->log_level);
174     ndmda_add_to_cmd(cmd, tmpbuf);
175   }
176 
177   ndmda_add_to_cmd(cmd, "-c");
178   ndmda_add_to_cmd(cmd, "-I#3");
179   add_env(&da->env_tab, cmd);
180 
181   ndma_send_logmsg(sess, NDMP9_LOG_DEBUG, sess->plumb.data, "CMD: %s", cmd);
182 
183   if (ndmda_pipe_fork_exec(sess, cmd, 1) < 0) { return NDMP9_UNDEFINED_ERR; }
184 
185   ndmis_data_start(sess, NDMCHAN_MODE_WRITE);
186 
187   da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
188   da->data_state.operation = NDMP9_DATA_OP_BACKUP;
189 
190   return error;
191 }
192 
ndmda_data_start_recover(struct ndm_session * sess)193 ndmp9_error ndmda_data_start_recover(struct ndm_session* sess)
194 {
195   struct ndm_data_agent* da = sess->data_acb;
196   ndmp9_error error = NDMP9_NO_ERR;
197   char cmd[NDMDA_MAX_CMD];
198 
199   strcpy(cmd, "wrap_");
200   strcat(cmd, da->bu_type);
201 
202   if (sess->param->log_level > 0) {
203     char tmpbuf[40];
204     snprintf(tmpbuf, sizeof(tmpbuf), "-d%d", sess->param->log_level);
205     ndmda_add_to_cmd(cmd, tmpbuf);
206   }
207 
208   ndmda_add_to_cmd(cmd, "-x");
209   ndmda_add_to_cmd(cmd, "-I#3");
210   add_env(&da->env_tab, cmd);
211   add_nlist(&da->nlist_tab, cmd);
212 
213   ndma_send_logmsg(sess, NDMP9_LOG_DEBUG, sess->plumb.data, "CMD: %s", cmd);
214 
215   if (ndmda_pipe_fork_exec(sess, cmd, 0) < 0) { return NDMP9_UNDEFINED_ERR; }
216 
217   ndmis_data_start(sess, NDMCHAN_MODE_READ);
218 
219   da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
220   da->data_state.operation = NDMP9_DATA_OP_RECOVER;
221 
222   return error;
223 }
224 
ndmda_data_start_recover_fh(struct ndm_session * sess)225 ndmp9_error ndmda_data_start_recover_fh(struct ndm_session* sess)
226 {
227   struct ndm_data_agent* da = sess->data_acb;
228   ndmp9_error error = NDMP9_NO_ERR;
229   char cmd[NDMDA_MAX_CMD];
230 
231   strcpy(cmd, "wrap_");
232   strcat(cmd, da->bu_type);
233   ndmda_add_to_cmd(cmd, "-t");
234   ndmda_add_to_cmd(cmd, "-I#3");
235   add_env(&da->env_tab, cmd);
236   add_nlist(&da->nlist_tab, cmd);
237 
238   ndma_send_logmsg(sess, NDMP9_LOG_DEBUG, sess->plumb.data, "CMD: %s", cmd);
239 
240   if (ndmda_pipe_fork_exec(sess, cmd, 0) < 0) { return NDMP9_UNDEFINED_ERR; }
241 
242   ndmis_data_start(sess, NDMCHAN_MODE_READ);
243 
244   da->data_state.state = NDMP9_DATA_STATE_ACTIVE;
245   da->data_state.operation = NDMP9_DATA_OP_RECOVER_FILEHIST;
246 
247   return error;
248 }
249 
ndmda_sync_state(struct ndm_session * sess)250 void ndmda_sync_state(struct ndm_session* sess)
251 { /* no-op, always accurate */
252 }
253 
ndmda_data_abort(struct ndm_session * sess)254 void ndmda_data_abort(struct ndm_session* sess)
255 {
256   ndmda_data_halt(sess, NDMP9_DATA_HALT_ABORTED);
257 }
258 
ndmda_sync_environment(struct ndm_session * sess)259 void ndmda_sync_environment(struct ndm_session* sess)
260 {
261   /* no-op, always accurate */
262 }
263 
ndmda_data_listen(struct ndm_session * sess)264 ndmp9_error ndmda_data_listen(struct ndm_session* sess)
265 {
266   struct ndm_data_agent* da = sess->data_acb;
267 
268   da->data_state.state = NDMP9_DATA_STATE_LISTEN;
269   da->data_state.halt_reason = NDMP9_DATA_HALT_NA;
270 
271   return NDMP9_NO_ERR;
272 }
273 
ndmda_data_connect(struct ndm_session * sess)274 ndmp9_error ndmda_data_connect(struct ndm_session* sess)
275 {
276   struct ndm_data_agent* da = sess->data_acb;
277 
278   da->data_state.state = NDMP9_DATA_STATE_CONNECTED;
279   da->data_state.halt_reason = NDMP9_DATA_HALT_NA;
280 
281   return NDMP9_NO_ERR;
282 }
283 
ndmda_data_halt(struct ndm_session * sess,ndmp9_data_halt_reason reason)284 void ndmda_data_halt(struct ndm_session* sess, ndmp9_data_halt_reason reason)
285 {
286   struct ndm_data_agent* da = sess->data_acb;
287 
288   da->data_state.state = NDMP9_DATA_STATE_HALTED;
289   da->data_state.halt_reason = reason;
290   da->data_notify_pending = 1;
291 
292   ndmda_fh_flush(sess);
293 
294   ndmis_data_close(sess);
295 
296   ndmchan_cleanup(&da->formatter_image);
297   ndmchan_cleanup(&da->formatter_error);
298   ndmchan_cleanup(&da->formatter_wrap);
299 
300   /* this needs to be better */
301   if (da->formatter_pid) {
302     sleep(1); /* give gtar a chance to stop by itself */
303     kill(da->formatter_pid, SIGTERM);
304   }
305 }
306 
ndmda_data_stop(struct ndm_session * sess)307 void ndmda_data_stop(struct ndm_session* sess) { ndmda_decommission(sess); }
308 
309 
310 /*
311  * Quantum -- get a bit of work done
312  ****************************************************************
313  */
314 
ndmda_quantum(struct ndm_session * sess)315 int ndmda_quantum(struct ndm_session* sess)
316 {
317   struct ndm_data_agent* da = sess->data_acb;
318   int did_something = 0; /* did nothing */
319 
320 
321   switch (da->data_state.state) {
322     default:
323       ndmalogf(sess, 0, 0, "BOTCH data state");
324       return -1;
325 
326     case NDMP9_DATA_STATE_IDLE:
327     case NDMP9_DATA_STATE_HALTED:
328     case NDMP9_DATA_STATE_CONNECTED:
329       break;
330 
331     case NDMP9_DATA_STATE_LISTEN:
332       switch (sess->plumb.image_stream->data_ep.connect_status) {
333         case NDMIS_CONN_LISTEN: /* no connection yet */
334           break;
335 
336         case NDMIS_CONN_ACCEPTED: /* we're in business */
337           /* drum roll please... */
338           da->data_state.state = NDMP9_DATA_STATE_CONNECTED;
339           /* tah-dah */
340           did_something++; /* did something */
341           break;
342 
343         case NDMIS_CONN_BOTCHED: /* accept() went south */
344         default:                 /* ain't suppose to happen */
345           ndmda_data_halt(sess, NDMP9_DATA_HALT_CONNECT_ERROR);
346           did_something++; /* did something */
347           break;
348       }
349       break;
350 
351     case NDMP9_DATA_STATE_ACTIVE:
352       did_something |= ndmda_quantum_stderr(sess);
353       did_something |= ndmda_quantum_wrap(sess);
354       did_something |= ndmda_quantum_image(sess);
355       break;
356   }
357 
358   ndmda_send_notice(sess);
359 
360   return did_something;
361 }
362 
ndmda_quantum_stderr(struct ndm_session * sess)363 int ndmda_quantum_stderr(struct ndm_session* sess)
364 {
365   struct ndm_data_agent* da = sess->data_acb;
366   struct ndmchan* ch = &da->formatter_error;
367   int did_something = 0;
368   char* p;
369   char* data;
370   char* pend;
371   unsigned n_ready;
372 
373 again:
374   n_ready = ndmchan_n_ready(ch);
375   if (n_ready == 0) return did_something;
376 
377   data = p = &ch->data[ch->beg_ix];
378   pend = p + n_ready;
379 
380   while (p < pend && *p != '\n') p++;
381 
382 
383   if (p < pend && *p == '\n') {
384     *p++ = 0;
385     ndma_send_logmsg(sess, NDMP9_LOG_NORMAL, sess->plumb.data, "%s", data);
386     ch->beg_ix += p - data;
387     did_something++;
388     goto again;
389   }
390 
391   if (!ch->eof) return did_something;
392 
393   /* content w/o newline, and EOF */
394   /* p == pend */
395   if (ch->end_ix >= ch->data_size) {
396     if (data != ch->data) {
397       ndmchan_compress(ch);
398       goto again;
399     }
400     /* that's one huge message */
401     p--; /* lose last byte */
402   }
403 
404   ch->data[ch->end_ix++] = '\n';
405   did_something++;
406   goto again;
407 }
408 
ndmda_quantum_wrap(struct ndm_session * sess)409 int ndmda_quantum_wrap(struct ndm_session* sess)
410 {
411   struct ndm_data_agent* da = sess->data_acb;
412   struct ndmchan* ch = &da->formatter_wrap;
413   int did_something = 0;
414   char* p;
415   char* data;
416   char* pend;
417   unsigned n_ready;
418   int is_recover = 0;
419 
420   switch (da->data_state.operation) {
421     default:
422       assert(0);
423       break;
424 
425     case NDMP9_DATA_OP_BACKUP:
426       break;
427 
428     case NDMP9_DATA_OP_RECOVER:
429     case NDMP9_DATA_OP_RECOVER_FILEHIST:
430       is_recover = 1;
431       break;
432   }
433 
434 again:
435   n_ready = ndmchan_n_ready(ch);
436   if (n_ready == 0) {
437     if (ch->eof && is_recover) {
438       ndmda_data_halt(sess, NDMP9_DATA_HALT_SUCCESSFUL);
439     }
440     return did_something;
441   }
442   data = p = &ch->data[ch->beg_ix];
443   pend = p + n_ready;
444 
445   while (p < pend && *p != '\n') p++;
446 
447 
448   if (p < pend && *p == '\n') {
449     *p++ = 0;
450     ndmda_wrap_in(sess, data);
451     ch->beg_ix += p - data;
452     did_something++;
453     goto again;
454   }
455 
456   if (!ch->eof) return did_something;
457 
458   /* content w/o newline, and EOF */
459   /* p == pend */
460   if (ch->end_ix >= ch->data_size) {
461     if (data != ch->data) {
462       ndmchan_compress(ch);
463       goto again;
464     }
465     /* that's one huge message */
466     p--; /* lose last byte */
467   }
468 
469   ch->data[ch->end_ix++] = '\n';
470   did_something++;
471   goto again;
472 }
473 
474 
ndmda_quantum_image(struct ndm_session * sess)475 int ndmda_quantum_image(struct ndm_session* sess)
476 {
477   struct ndm_data_agent* da = sess->data_acb;
478   struct ndmchan* from_chan;
479   struct ndmchan* to_chan;
480   unsigned n_ready, n_avail, n_copy;
481   int is_backup = 0;
482 
483   switch (da->data_state.operation) {
484     default:
485       assert(0);
486       from_chan = 0;
487       to_chan = 0;
488       break;
489 
490     case NDMP9_DATA_OP_BACKUP:
491       from_chan = &da->formatter_image;
492       to_chan = &sess->plumb.image_stream->chan;
493       is_backup = 1;
494       break;
495 
496     case NDMP9_DATA_OP_RECOVER:
497     case NDMP9_DATA_OP_RECOVER_FILEHIST:
498       from_chan = &sess->plumb.image_stream->chan;
499       to_chan = &da->formatter_image;
500       break;
501   }
502 
503 again:
504   n_copy = n_ready = ndmchan_n_ready(from_chan);
505   if (n_ready == 0) {
506     if (from_chan->eof) {
507       to_chan->eof = 1;
508       if (ndmchan_n_ready(to_chan) == 0) {
509         if (is_backup) { ndmda_data_halt(sess, NDMP9_DATA_HALT_SUCCESSFUL); }
510       }
511     }
512     return 0; /* data blocked */
513   }
514 
515   n_avail = ndmchan_n_avail(to_chan);
516   if (n_copy > n_avail) n_copy = n_avail;
517 
518   if (da->enable_hist) {
519     if (n_copy > da->pass_resid) n_copy = da->pass_resid;
520   }
521 
522   if (n_copy > 0) {
523     bcopy(&from_chan->data[from_chan->beg_ix], &to_chan->data[to_chan->end_ix],
524           n_copy);
525     from_chan->beg_ix += n_copy;
526     to_chan->end_ix += n_copy;
527     da->data_state.bytes_processed += n_copy;
528     da->pass_resid -= n_copy;
529     goto again; /* do as much as possible */
530   }
531 
532   return 0;
533 }
534 
535 
536 /*
537  * Process WRAP messages from the formatter. Called from
538  * ndmda_quantum_wrap(). The formatter sends one line text
539  * messages via the WRAP pipe (fd=3 on formatter).
540  * The WRAP message contain log messages, file history,
541  * status updates, etc, etc, etc.
542  *
543  * Here the messages are parsed and directed to the
544  * right NDMP interface toward the Control Agent.
545  */
546 
547 void ndmp9_fstat_from_wrap_fstat(ndmp9_file_stat* fstat9,
548                                  struct wrap_fstat* fstatw);
549 
ndmda_wrap_in(struct ndm_session * sess,char * wrap_line)550 int ndmda_wrap_in(struct ndm_session* sess, char* wrap_line)
551 {
552   struct wrap_msg_buf _wmsg, *wmsg = &_wmsg;
553   int rc;
554   ndmp9_file_stat fstat9;
555 
556   NDMOS_MACRO_ZEROFILL(wmsg);
557 
558   rc = wrap_parse_msg(wrap_line, wmsg);
559   if (rc != 0) {
560     ndmalogf(sess, 0, 2, "Malformed wrap: %s", wrap_line);
561     return -1;
562   }
563 
564   switch (wmsg->msg_type) {
565     case WRAP_MSGTYPE_LOG_MESSAGE:
566       ndmalogf(sess, "WRAP", 2, "%s", wmsg->body.log_message.message);
567       ndma_send_logmsg(sess, NDMP9_LOG_NORMAL, sess->plumb.data, "WRAP: %s",
568                        wmsg->body.log_message.message);
569       break;
570 
571     case WRAP_MSGTYPE_ADD_FILE:
572       ndmp9_fstat_from_wrap_fstat(&fstat9, &wmsg->body.add_file.fstat);
573       fstat9.fh_info.valid = NDMP9_VALIDITY_VALID;
574       fstat9.fh_info.value = wmsg->body.add_file.fhinfo;
575       ndmda_fh_add_file(sess, &fstat9, wmsg->body.add_file.path);
576       break;
577 
578     case WRAP_MSGTYPE_ADD_DIRENT:
579       ndmda_fh_add_dir(sess, wmsg->body.add_dirent.dir_fileno,
580                        wmsg->body.add_dirent.name,
581                        wmsg->body.add_dirent.fileno);
582       break;
583 
584     case WRAP_MSGTYPE_ADD_NODE:
585       ndmp9_fstat_from_wrap_fstat(&fstat9, &wmsg->body.add_node.fstat);
586       fstat9.fh_info.valid = NDMP9_VALIDITY_VALID;
587       fstat9.fh_info.value = wmsg->body.add_node.fhinfo;
588       ndmda_fh_add_node(sess, &fstat9);
589       break;
590 
591     case WRAP_MSGTYPE_DATA_READ:
592       ndmda_send_data_read(sess, wmsg->body.data_read.offset,
593                            wmsg->body.data_read.length);
594       break;
595 
596     case WRAP_MSGTYPE_ADD_ENV:
597     case WRAP_MSGTYPE_DATA_STATS:
598     case WRAP_MSGTYPE_RECOVERY_RESULT:
599       ndmalogf(sess, 0, 2, "Unimplemented wrap: %s", wrap_line);
600       break;
601   }
602 
603   return 0;
604 }
605 
ndmp9_fstat_from_wrap_fstat(ndmp9_file_stat * fstat9,struct wrap_fstat * fstatw)606 void ndmp9_fstat_from_wrap_fstat(ndmp9_file_stat* fstat9,
607                                  struct wrap_fstat* fstatw)
608 {
609   NDMOS_MACRO_ZEROFILL(fstat9);
610 
611   switch (fstatw->ftype) {
612     default:
613     case WRAP_FTYPE_INVALID:
614       fstat9->ftype = NDMP9_FILE_OTHER;
615       break;
616     case WRAP_FTYPE_DIR:
617       fstat9->ftype = NDMP9_FILE_DIR;
618       break;
619     case WRAP_FTYPE_FIFO:
620       fstat9->ftype = NDMP9_FILE_FIFO;
621       break;
622     case WRAP_FTYPE_CSPEC:
623       fstat9->ftype = NDMP9_FILE_CSPEC;
624       break;
625     case WRAP_FTYPE_BSPEC:
626       fstat9->ftype = NDMP9_FILE_BSPEC;
627       break;
628     case WRAP_FTYPE_REG:
629       fstat9->ftype = NDMP9_FILE_REG;
630       break;
631     case WRAP_FTYPE_SLINK:
632       fstat9->ftype = NDMP9_FILE_SLINK;
633       break;
634     case WRAP_FTYPE_SOCK:
635       fstat9->ftype = NDMP9_FILE_SOCK;
636       break;
637     case WRAP_FTYPE_REGISTRY:
638       fstat9->ftype = NDMP9_FILE_REGISTRY;
639       break;
640     case WRAP_FTYPE_OTHER:
641       fstat9->ftype = NDMP9_FILE_OTHER;
642       break;
643   }
644 
645   if (fstatw->valid & WRAP_FSTAT_VALID_FTYPE) {}
646 
647   if (fstatw->valid & WRAP_FSTAT_VALID_MODE) {
648     fstat9->mode.valid = NDMP9_VALIDITY_VALID;
649     fstat9->mode.value = fstatw->mode;
650   }
651 
652   if (fstatw->valid & WRAP_FSTAT_VALID_SIZE) {
653     fstat9->size.valid = NDMP9_VALIDITY_VALID;
654     fstat9->size.value = fstatw->size;
655   }
656 
657   if (fstatw->valid & WRAP_FSTAT_VALID_LINKS) {
658     fstat9->links.valid = NDMP9_VALIDITY_VALID;
659     fstat9->links.value = fstatw->size;
660   }
661 
662   if (fstatw->valid & WRAP_FSTAT_VALID_UID) {
663     fstat9->uid.valid = NDMP9_VALIDITY_VALID;
664     fstat9->uid.value = fstatw->uid;
665   }
666 
667   if (fstatw->valid & WRAP_FSTAT_VALID_GID) {
668     fstat9->gid.valid = NDMP9_VALIDITY_VALID;
669     fstat9->gid.value = fstatw->gid;
670   }
671 
672   if (fstatw->valid & WRAP_FSTAT_VALID_ATIME) {
673     fstat9->atime.valid = NDMP9_VALIDITY_VALID;
674     fstat9->atime.value = fstatw->atime;
675   }
676 
677   if (fstatw->valid & WRAP_FSTAT_VALID_MTIME) {
678     fstat9->mtime.valid = NDMP9_VALIDITY_VALID;
679     fstat9->mtime.value = fstatw->mtime;
680   }
681 
682   if (fstatw->valid & WRAP_FSTAT_VALID_CTIME) {
683     fstat9->ctime.valid = NDMP9_VALIDITY_VALID;
684     fstat9->ctime.value = fstatw->ctime;
685   }
686 
687   if (fstatw->valid & WRAP_FSTAT_VALID_FILENO) {
688     fstat9->node.valid = NDMP9_VALIDITY_VALID;
689     fstat9->node.value = fstatw->fileno;
690   }
691 }
692 
693 
694 /*
695  * Send LOG and NOTIFY messages
696  ****************************************************************
697  */
698 
ndmda_send_notice(struct ndm_session * sess)699 void ndmda_send_notice(struct ndm_session* sess)
700 {
701   struct ndm_data_agent* da = sess->data_acb;
702 
703   if (!da->data_notify_pending) return;
704 
705   da->data_notify_pending = 0;
706 
707   switch (da->data_state.state) {
708     case NDMP9_DATA_STATE_HALTED:
709       ndma_notify_data_halted(sess);
710       break;
711 
712     default:
713       /* Hmm. Why are we here. Race? */
714       break;
715   }
716 }
717 
ndmda_send_data_read(struct ndm_session * sess,uint64_t offset,uint64_t length)718 void ndmda_send_data_read(struct ndm_session* sess,
719                           uint64_t offset,
720                           uint64_t length)
721 {
722   struct ndm_data_agent* da = sess->data_acb;
723   ndmp9_addr_type addr_type;
724 
725   addr_type = da->data_state.data_connection_addr.addr_type;
726 
727   if (NDMP9_ADDR_LOCAL == addr_type) {
728 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
729     if (ndmta_local_mover_read(sess, offset, length) != 0) {
730       ndma_send_logmsg(sess, NDMP9_LOG_ERROR, sess->plumb.data,
731                        "local_mover_read failed");
732       ndmda_data_halt(sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
733     }
734 #else  /* !NDMOS_OPTION_NO_TAPE_AGENT */
735     ndma_send_logmsg(sess, NDMP9_LOG_ERROR, sess->plumb.data,
736                      "local_mover_read not configured");
737     ndmda_data_halt(sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
738 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
739     return;
740   }
741 
742   switch (addr_type) {
743     case NDMP9_ADDR_TCP:
744       ndma_notify_data_read(sess, offset, length);
745       break;
746 
747     default:
748       ndma_send_logmsg(sess, NDMP9_LOG_ERROR, sess->plumb.data,
749                        "bogus mover.addr_type");
750       ndmda_data_halt(sess, NDMP9_DATA_HALT_INTERNAL_ERROR);
751       break;
752   }
753 }
754 
755 
756 /*
757  * Misc -- env[] and nlist[] subroutines, etc
758  ****************************************************************
759  */
760 
ndmda_copy_environment(struct ndm_session * sess,ndmp9_pval * env,unsigned n_env)761 int ndmda_copy_environment(struct ndm_session* sess,
762                            ndmp9_pval* env,
763                            unsigned n_env)
764 {
765   struct ndm_data_agent* da = sess->data_acb;
766   unsigned int i;
767 
768   for (i = 0; i < n_env; i++) {
769     if (!ndma_store_env_list(&da->env_tab, &env[i])) goto fail;
770   }
771 
772   return 0;
773 
774 fail:
775   ndma_destroy_env_list(&da->env_tab);
776 
777   return -1;
778 }
779 
ndmda_find_env(struct ndm_session * sess,char * name)780 struct ndmp9_pval* ndmda_find_env(struct ndm_session* sess, char* name)
781 {
782   struct ndm_data_agent* da = sess->data_acb;
783   struct ndm_env_entry* entry;
784 
785   for (entry = da->env_tab.head; entry; entry = entry->next) {
786     if (strcmp(entry->pval.name, name) == 0) return &entry->pval;
787   }
788 
789   return 0;
790 }
791 
792 
ndmda_interpret_boolean_value(char * value_str,int default_value)793 int ndmda_interpret_boolean_value(char* value_str, int default_value)
794 {
795   if (strcasecmp(value_str, "y") == 0 || strcasecmp(value_str, "yes") == 0 ||
796       strcasecmp(value_str, "t") == 0 || strcasecmp(value_str, "true") == 0 ||
797       strcasecmp(value_str, "1") == 0)
798     return 1;
799 
800   if (strcasecmp(value_str, "n") == 0 || strcasecmp(value_str, "no") == 0 ||
801       strcasecmp(value_str, "f") == 0 || strcasecmp(value_str, "false") == 0 ||
802       strcasecmp(value_str, "0") == 0)
803     return 0;
804 
805   return default_value;
806 }
807 
ndmda_purge_environment(struct ndm_session * sess)808 void ndmda_purge_environment(struct ndm_session* sess)
809 {
810   struct ndm_data_agent* da = sess->data_acb;
811 
812   ndma_destroy_env_list(&da->env_tab);
813 }
814 
815 
ndmda_copy_nlist(struct ndm_session * sess,ndmp9_name * nlist,unsigned n_nlist)816 int ndmda_copy_nlist(struct ndm_session* sess,
817                      ndmp9_name* nlist,
818                      unsigned n_nlist)
819 {
820   struct ndm_data_agent* da = sess->data_acb;
821   unsigned int i;
822 
823   for (i = 0; i < n_nlist; i++) {
824     if (!ndma_store_nlist(&da->nlist_tab, &nlist[i])) {
825       return -1; /* no mem */
826     }
827   }
828 
829   /* TODO: sort */
830 
831   return 0;
832 }
833 
ndmda_purge_nlist(struct ndm_session * sess)834 void ndmda_purge_nlist(struct ndm_session* sess)
835 {
836   struct ndm_data_agent* da = sess->data_acb;
837 
838   ndma_destroy_nlist(&da->nlist_tab);
839 }
840 
ndmda_count_invalid_fh_info(struct ndm_session * sess)841 int ndmda_count_invalid_fh_info(struct ndm_session* sess)
842 {
843   struct ndm_data_agent* da = sess->data_acb;
844   struct ndm_nlist_entry* entry;
845   int count;
846 
847   count = 0;
848   for (entry = da->nlist_tab.head; entry; entry = entry->next) {
849     if (entry->name.fh_info.valid != NDMP9_VALIDITY_VALID) { count++; }
850   }
851 
852   return count;
853 }
854 
ndmda_count_invalid_fh_info_pending(struct ndm_session * sess)855 int ndmda_count_invalid_fh_info_pending(struct ndm_session* sess)
856 {
857   struct ndm_data_agent* da = sess->data_acb;
858   struct ndm_nlist_entry* entry;
859   int count;
860 
861   count = 0;
862   for (entry = da->nlist_tab.head; entry; entry = entry->next) {
863     if (entry->result_err == NDMP9_UNDEFINED_ERR &&
864         entry->name.fh_info.valid != NDMP9_VALIDITY_VALID) {
865       count++;
866     }
867   }
868 
869   return count;
870 }
871 
872 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
873