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