s3: Use dbwrap_parse_record in fetch_share_mode_unlocked
[kai/samba.git] / source3 / rpcclient / cmd_fss.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * File Server Remote VSS Protocol (FSRVP) client
5  *
6  * Copyright (C) David Disseldorp 2012
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23 #include "rpcclient.h"
24 #include "../librpc/gen_ndr/ndr_fsrvp.h"
25 #include "../librpc/gen_ndr/ndr_fsrvp_c.h"
26
27 struct fss_context_map {
28         uint32_t ctx_val;
29         const char *ctx_str;
30         const char *ctx_desc;
31 };
32 struct fss_context_map ctx_map[] = {
33         {
34                 .ctx_val = FSRVP_CTX_BACKUP,
35                 .ctx_str = "backup",
36                 .ctx_desc = "auto-release, non-persistent shadow-copy.",
37         },
38         {
39                 .ctx_val = FSRVP_CTX_FILE_SHARE_BACKUP,
40                 .ctx_str = "file_share_backup",
41                 .ctx_desc = "auto-release, non-persistent shadow-copy created "
42                             "without writer involvement.",
43         },
44         {
45                 .ctx_val = FSRVP_CTX_NAS_ROLLBACK,
46                 .ctx_str = "nas_rollback",
47                 .ctx_desc = "non-auto-release, persistent shadow-copy created "
48                             "without writer involvement.",
49         },
50         {
51                 .ctx_val = FSRVP_CTX_APP_ROLLBACK,
52                 .ctx_str = "app_rollback",
53                 .ctx_desc = "non-auto-release, persistent shadow-copy.",
54         },
55         { 0, NULL, NULL },
56 };
57
58 static bool map_fss_ctx_str(const char *ctx_str,
59                             uint32_t *ctx_val)
60 {
61         int i;
62
63         for (i = 0; ctx_map[i].ctx_str != NULL; i++) {
64                 if (!strcmp(ctx_map[i].ctx_str, ctx_str)) {
65                         *ctx_val = ctx_map[i].ctx_val;
66                         return true;
67                 }
68         }
69         return false;
70 }
71
72 static void cmd_fss_is_path_sup_usage(const char *script_name)
73 {
74         printf("usage: %s [share_name]\n", script_name);
75 }
76
77 static NTSTATUS cmd_fss_is_path_sup(struct rpc_pipe_client *cli,
78                                     TALLOC_CTX *mem_ctx, int argc,
79                                     const char **argv)
80 {
81         NTSTATUS status;
82         struct fss_IsPathSupported r;
83         struct dcerpc_binding_handle *b = cli->binding_handle;
84
85         if (argc != 2) {
86                 cmd_fss_is_path_sup_usage(argv[0]);
87                 return NT_STATUS_UNSUCCESSFUL;
88         }
89
90         ZERO_STRUCT(r);
91         r.in.ShareName = talloc_asprintf(mem_ctx, "%s\\%s",
92                                          cli->srv_name_slash, argv[1]);
93         if (r.in.ShareName == NULL) {
94                 return NT_STATUS_NO_MEMORY;
95         }
96
97         status = dcerpc_fss_IsPathSupported_r(b, mem_ctx, &r);
98         if (!NT_STATUS_IS_OK(status)) {
99                 DEBUG(0, ("IsPathSupported failed with UNC %s\n",
100                           r.in.ShareName));
101                 return NT_STATUS_UNSUCCESSFUL;
102         } else if (r.out.result) {
103                 DEBUG(0, ("failed IsPathSupported response: 0x%x\n",
104                           r.out.result));
105                 return NT_STATUS_UNSUCCESSFUL;
106         }
107         printf("UNC %s %s shadow copy requests\n", r.in.ShareName,
108                *r.out.SupportedByThisProvider ? "supports" : "does not support");
109
110         return NT_STATUS_OK;
111 }
112
113 static void cmd_fss_get_sup_version_usage(const char *script_name)
114 {
115         printf("usage: %s\n", script_name);
116 }
117
118 static NTSTATUS cmd_fss_get_sup_version(struct rpc_pipe_client *cli,
119                                     TALLOC_CTX *mem_ctx, int argc,
120                                     const char **argv)
121 {
122         NTSTATUS status;
123         struct fss_GetSupportedVersion r;
124         struct dcerpc_binding_handle *b = cli->binding_handle;
125
126         if (argc != 1) {
127                 cmd_fss_get_sup_version_usage(argv[0]);
128                 return NT_STATUS_UNSUCCESSFUL;
129         }
130
131         ZERO_STRUCT(r);
132         status = dcerpc_fss_GetSupportedVersion_r(b, mem_ctx, &r);
133         if (!NT_STATUS_IS_OK(status) || (r.out.result != 0)) {
134                 DEBUG(0, ("GetSupportedVersion failed: %s result: 0x%x\n",
135                           nt_errstr(status), r.out.result));
136                 return NT_STATUS_UNSUCCESSFUL;
137         }
138         printf("server %s supports FSRVP versions from %u to %u\n",
139                cli->desthost, *r.out.MinVersion, *r.out.MaxVersion);
140
141         return NT_STATUS_OK;
142 }
143
144 static void cmd_fss_create_expose_usage(const char *script_name)
145 {
146         int i;
147
148         printf("usage: %s [fss_context] [ro|rw] [share1] <share2> ...\n"
149                "[fss_context] values:\n", script_name);
150         for (i = 0; ctx_map[i].ctx_str != NULL; i++) {
151                 printf("\t%s: %s\n", ctx_map[i].ctx_str, ctx_map[i].ctx_desc);
152         }
153 }
154
155 static NTSTATUS cmd_fss_create_expose_parse(TALLOC_CTX *mem_ctx, int argc,
156                                             const char **argv,
157                                             const char *desthost,
158                                             uint32_t *fss_ctx_val,
159                                             int *num_maps,
160                                          struct fssagent_share_mapping_1 **maps)
161 {
162         int num_non_share_args = 3;
163         int num_share_args;
164         int i;
165         struct fssagent_share_mapping_1 *map_array;
166
167         if (argc < 4) {
168                 return NT_STATUS_INVALID_PARAMETER;
169         }
170
171         if (!map_fss_ctx_str(argv[1], fss_ctx_val)) {
172                 return NT_STATUS_INVALID_PARAMETER;
173         }
174
175         if (!strcmp(argv[2], "rw")) {
176                 /* shadow-copy is created as read-write */
177                 *fss_ctx_val |= ATTR_AUTO_RECOVERY;
178         } else if (strcmp(argv[2], "ro")) {
179                 return NT_STATUS_INVALID_PARAMETER;
180         }
181
182         num_share_args = argc - num_non_share_args;
183         map_array = talloc_array(mem_ctx, struct fssagent_share_mapping_1,
184                                  num_share_args);
185         if (map_array == NULL) {
186                 return NT_STATUS_NO_MEMORY;
187         }
188
189         for (i = 0; i < num_share_args; i++) {
190                 map_array[i].ShareNameUNC = talloc_asprintf(mem_ctx, "\\\\%s\\%s",
191                                         desthost, argv[i + num_non_share_args]);
192                 if (map_array[i].ShareNameUNC == NULL) {
193                         return NT_STATUS_NO_MEMORY;
194                 }
195         }
196         *num_maps = num_share_args;
197         *maps = map_array;
198
199         return NT_STATUS_OK;
200 }
201
202 static NTSTATUS cmd_fss_create_expose(struct rpc_pipe_client *cli,
203                                      TALLOC_CTX *mem_ctx, int argc,
204                                      const char **argv)
205 {
206         NTSTATUS status;
207         struct fss_GetSupportedVersion r_version_get;
208         struct fss_SetContext r_context_set;
209         struct fss_StartShadowCopySet r_scset_start;
210         struct fss_PrepareShadowCopySet r_scset_prep;
211         struct fss_CommitShadowCopySet r_scset_commit;
212         struct fss_ExposeShadowCopySet r_scset_expose;
213         struct dcerpc_binding_handle *b = cli->binding_handle;
214         time_t start_time;
215         TALLOC_CTX *tmp_ctx;
216         uint32_t fss_ctx_val;
217         int num_maps;
218         struct fssagent_share_mapping_1 *req_maps;
219         int i;
220
221         tmp_ctx = talloc_new(mem_ctx);
222         if (tmp_ctx == NULL) {
223                 return NT_STATUS_NO_MEMORY;
224         }
225
226         status = cmd_fss_create_expose_parse(tmp_ctx, argc, argv, cli->desthost,
227                                             &fss_ctx_val, &num_maps, &req_maps);
228         if (!NT_STATUS_IS_OK(status)) {
229                 cmd_fss_create_expose_usage(argv[0]);
230                 goto err_out;
231         }
232
233         /*
234          * PrepareShadowCopySet & CommitShadowCopySet often exceed the default
235          * 60 second dcerpc request timeout against Windows Server "8" Beta.
236          * ACHTUNG! dcerpc_binding_handle_set_timeout() value is interpreted as
237          * seconds on a source4 transport and as msecs here.
238          */
239         dcerpc_binding_handle_set_timeout(b, 240 * 1000);
240
241         for (i = 0; i < num_maps; i++) {
242                 struct fss_IsPathSupported r_pathsupport_get;
243                 r_pathsupport_get.in.ShareName = req_maps[i].ShareNameUNC;
244                 status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get);
245                 if (!NT_STATUS_IS_OK(status) || (r_pathsupport_get.out.result != 0)) {
246                         DEBUG(0, ("IsPathSupported failed: %s result: 0x%x\n",
247                                   nt_errstr(status), r_pathsupport_get.out.result));
248                         goto err_out;
249                 }
250                 if (!r_pathsupport_get.out.SupportedByThisProvider) {
251                         printf("path %s does not supported shadow-copies\n",
252                                req_maps[i].ShareNameUNC);
253                         status = NT_STATUS_NOT_SUPPORTED;
254                         goto err_out;
255                 }
256         }
257
258         ZERO_STRUCT(r_version_get);
259         status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get);
260         if (!NT_STATUS_IS_OK(status) || (r_version_get.out.result != 0)) {
261                 DEBUG(0, ("GetSupportedVersion failed: %s result: 0x%x\n",
262                           nt_errstr(status), r_version_get.out.result));
263                 goto err_out;
264         }
265
266         ZERO_STRUCT(r_context_set);
267         r_context_set.in.Context = fss_ctx_val;
268         status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set);
269         if (!NT_STATUS_IS_OK(status) || (r_context_set.out.result != 0)) {
270                 DEBUG(0, ("SetContext failed: %s result: 0x%x\n",
271                           nt_errstr(status), r_context_set.out.result));
272                 goto err_out;
273         }
274
275         ZERO_STRUCT(r_scset_start);
276         r_scset_start.in.ClientShadowCopySetId = GUID_random();
277         status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start);
278         if (!NT_STATUS_IS_OK(status) || (r_scset_start.out.result != 0)) {
279                 DEBUG(0, ("StartShadowCopySet failed: %s result: 0x%x\n",
280                           nt_errstr(status), r_scset_start.out.result));
281                 goto err_out;
282         }
283         printf("%s: shadow-copy set created\n",
284                GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId));
285
286         for (i = 0; i < num_maps; i++) {
287                 struct fss_AddToShadowCopySet r_scset_add;
288                 r_scset_add.in.ClientShadowCopyId = GUID_random();
289                 r_scset_add.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
290                 r_scset_add.in.ShareName = req_maps[i].ShareNameUNC;
291                 status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add);
292                 if (!NT_STATUS_IS_OK(status) || (r_scset_add.out.result != 0)) {
293                         DEBUG(0, ("AddToShadowCopySet failed: %s result: 0x%x\n",
294                                   nt_errstr(status), r_scset_add.out.result));
295                         goto err_out;
296                 }
297                 printf("%s(%s): %s shadow-copy added to set\n",
298                        GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
299                        GUID_string(tmp_ctx, r_scset_add.out.pShadowCopyId),
300                        r_scset_add.in.ShareName);
301                 req_maps[i].ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
302                 req_maps[i].ShadowCopyId = *r_scset_add.out.pShadowCopyId;
303         }
304
305         start_time = time_mono(NULL);
306         ZERO_STRUCT(r_scset_prep);
307         r_scset_prep.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
308         r_scset_prep.in.TimeOutInMilliseconds = (240 * 1000);
309         status = dcerpc_fss_PrepareShadowCopySet_r(b, tmp_ctx, &r_scset_prep);
310         if (!NT_STATUS_IS_OK(status) || (r_scset_prep.out.result != 0)) {
311                 DEBUG(0, ("PrepareShadowCopySet failed: %s result: 0x%x\n",
312                           nt_errstr(status), r_scset_prep.out.result));
313                 goto err_out;
314         }
315         printf("%s: prepare completed in %llu secs\n",
316                GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
317                (long long unsigned int)(time_mono(NULL) - start_time));
318
319         start_time = time_mono(NULL);
320         ZERO_STRUCT(r_scset_commit);
321         r_scset_commit.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
322         r_scset_commit.in.TimeOutInMilliseconds = (180 * 1000); /* win8 */
323         status = dcerpc_fss_CommitShadowCopySet_r(b, tmp_ctx, &r_scset_commit);
324         if (!NT_STATUS_IS_OK(status) || (r_scset_commit.out.result != 0)) {
325                 DEBUG(0, ("CommitShadowCopySet failed: %s result: 0x%x\n",
326                           nt_errstr(status), r_scset_commit.out.result));
327                 goto err_out;
328         }
329         printf("%s: commit completed in %llu secs\n",
330                GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
331                (long long unsigned int)(time_mono(NULL) - start_time));
332
333         ZERO_STRUCT(r_scset_expose);
334         r_scset_expose.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
335         r_scset_expose.in.TimeOutInMilliseconds = (120 * 1000); /* win8 */
336         status = dcerpc_fss_ExposeShadowCopySet_r(b, tmp_ctx, &r_scset_expose);
337         if (!NT_STATUS_IS_OK(status) || (r_scset_expose.out.result != 0)) {
338                 DEBUG(0, ("ExposeShadowCopySet failed: %s result: 0x%x\n",
339                           nt_errstr(status), r_scset_expose.out.result));
340                 goto err_out;
341         }
342
343         for (i = 0; i < num_maps; i++) {
344                 struct fss_GetShareMapping r_sharemap_get;
345                 struct fssagent_share_mapping_1 *map;
346                 r_sharemap_get.in.ShadowCopyId = req_maps[i].ShadowCopyId;
347                 r_sharemap_get.in.ShadowCopySetId = req_maps[i].ShadowCopySetId;
348                 r_sharemap_get.in.ShareName = req_maps[i].ShareNameUNC;
349                 r_sharemap_get.in.Level = 1;
350                 status = dcerpc_fss_GetShareMapping_r(b, tmp_ctx, &r_sharemap_get);
351                 if (!NT_STATUS_IS_OK(status) || (r_sharemap_get.out.result != 0)) {
352                         DEBUG(0, ("GetShareMapping failed: %s result: 0x%x\n",
353                                   nt_errstr(status), r_sharemap_get.out.result));
354                         goto err_out;
355                 }
356                 map = r_sharemap_get.out.ShareMapping->ShareMapping1;
357                 printf("%s(%s): share %s exposed as a snapshot of %s\n",
358                        GUID_string(tmp_ctx, &map->ShadowCopySetId),
359                        GUID_string(tmp_ctx, &map->ShadowCopyId),
360                        map->ShadowCopyShareName, map->ShareNameUNC);
361         }
362
363 err_out:
364         talloc_free(tmp_ctx);
365         return status;
366 }
367
368 static void cmd_fss_delete_usage(const char *script_name)
369 {
370         printf("usage: %s [base_share] [shadow_copy_set_id] [shadow_copy_id]\n",
371                script_name);
372 }
373
374 static NTSTATUS cmd_fss_delete(struct rpc_pipe_client *cli,
375                                TALLOC_CTX *mem_ctx, int argc,
376                                const char **argv)
377 {
378         struct dcerpc_binding_handle *b = cli->binding_handle;
379         struct fss_DeleteShareMapping r_sharemap_del;
380         const char *sc_set_id;
381         const char *sc_id;
382         NTSTATUS status;
383         TALLOC_CTX *tmp_ctx;
384
385         if (argc < 4) {
386                 cmd_fss_delete_usage(argv[0]);
387                 return NT_STATUS_UNSUCCESSFUL;
388         }
389         sc_set_id = argv[2];
390         sc_id = argv[3];
391
392         tmp_ctx = talloc_new(mem_ctx);
393         if (tmp_ctx == NULL) {
394                 return NT_STATUS_NO_MEMORY;
395         }
396
397         ZERO_STRUCT(r_sharemap_del);
398         r_sharemap_del.in.ShareName = talloc_asprintf(tmp_ctx, "\\\\%s\\%s",
399                                                       cli->desthost, argv[1]);
400         if (r_sharemap_del.in.ShareName == NULL) {
401                 status = NT_STATUS_NO_MEMORY;
402                 goto err_out;
403         }
404         status = GUID_from_string(sc_set_id, &r_sharemap_del.in.ShadowCopySetId);
405         if (!NT_STATUS_IS_OK(status)) {
406                 DEBUG(0, ("Invalid shadow_copy_set_id parameter\n"));
407                 goto err_out;
408         }
409         status = GUID_from_string(sc_id, &r_sharemap_del.in.ShadowCopyId);
410         if (!NT_STATUS_IS_OK(status)) {
411                 DEBUG(0, ("Invalid shadow_copy_id parameter\n"));
412                 goto err_out;
413         }
414         status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del);
415         if (!NT_STATUS_IS_OK(status)) {
416                 DEBUG(0, ("DeleteShareMapping failed\n"));
417                 goto err_out;
418         } else if (r_sharemap_del.out.result != 0) {
419                 DEBUG(0, ("failed DeleteShareMapping response: 0x%x\n",
420                           r_sharemap_del.out.result));
421                 status = NT_STATUS_UNSUCCESSFUL;
422                 goto err_out;
423         }
424
425         printf("%s(%s): %s shadow-copy deleted\n",
426                sc_set_id, sc_id, r_sharemap_del.in.ShareName);
427
428 err_out:
429         talloc_free(tmp_ctx);
430         return status;
431 }
432
433 static void cmd_fss_is_shadow_copied_usage(const char *script_name)
434 {
435         printf("usage: %s [share_name]\n", script_name);
436 }
437
438 static NTSTATUS cmd_fss_is_shadow_copied(struct rpc_pipe_client *cli,
439                                          TALLOC_CTX *mem_ctx, int argc,
440                                          const char **argv)
441 {
442         NTSTATUS status;
443         struct fss_IsPathShadowCopied r;
444         struct dcerpc_binding_handle *b = cli->binding_handle;
445
446         if (argc != 2) {
447                 cmd_fss_is_shadow_copied_usage(argv[0]);
448                 return NT_STATUS_UNSUCCESSFUL;
449         }
450
451         ZERO_STRUCT(r);
452         r.in.ShareName = talloc_asprintf(mem_ctx, "%s\\%s",
453                                          cli->srv_name_slash, argv[1]);
454         if (r.in.ShareName == NULL) {
455                 return NT_STATUS_NO_MEMORY;
456         }
457
458         status = dcerpc_fss_IsPathShadowCopied_r(b, mem_ctx, &r);
459         if (!NT_STATUS_IS_OK(status)) {
460                 DEBUG(0, ("IsPathShadowCopied failed with UNC %s\n",
461                           r.in.ShareName));
462                 return NT_STATUS_UNSUCCESSFUL;
463         } else if (r.out.result) {
464                 DEBUG(0, ("failed IsPathShadowCopied response: 0x%x\n",
465                           r.out.result));
466                 return NT_STATUS_UNSUCCESSFUL;
467         }
468         printf("UNC %s %s an associated shadow-copy with compatibility 0x%x\n",
469                r.in.ShareName,
470                *r.out.ShadowCopyPresent ? "has" : "does not have",
471                *r.out.ShadowCopyCompatibility);
472
473         return NT_STATUS_OK;
474 }
475
476 static void cmd_fss_get_mapping_usage(const char *script_name)
477 {
478         printf("usage: %s [base_share] [shadow_copy_set_id] [shadow_copy_id]\n",
479                script_name);
480 }
481
482 static NTSTATUS cmd_fss_get_mapping(struct rpc_pipe_client *cli,
483                                     TALLOC_CTX *mem_ctx, int argc,
484                                     const char **argv)
485 {
486         struct dcerpc_binding_handle *b = cli->binding_handle;
487         struct fss_GetShareMapping r_sharemap_get;
488         const char *sc_set_id;
489         const char *sc_id;
490         struct fssagent_share_mapping_1 *map;
491         NTSTATUS status;
492         TALLOC_CTX *tmp_ctx;
493
494         if (argc < 4) {
495                 cmd_fss_get_mapping_usage(argv[0]);
496                 return NT_STATUS_UNSUCCESSFUL;
497         }
498         sc_set_id = argv[2];
499         sc_id = argv[3];
500
501         tmp_ctx = talloc_new(mem_ctx);
502         if (tmp_ctx == NULL) {
503                 return NT_STATUS_NO_MEMORY;
504         }
505
506         ZERO_STRUCT(r_sharemap_get);
507         r_sharemap_get.in.ShareName = talloc_asprintf(tmp_ctx, "\\\\%s\\%s",
508                                                       cli->desthost, argv[1]);
509         if (r_sharemap_get.in.ShareName == NULL) {
510                 status = NT_STATUS_NO_MEMORY;
511                 goto err_out;
512         }
513         status = GUID_from_string(sc_set_id, &r_sharemap_get.in.ShadowCopySetId);
514         if (!NT_STATUS_IS_OK(status)) {
515                 DEBUG(0, ("Invalid shadow_copy_set_id parameter\n"));
516                 goto err_out;
517         }
518         status = GUID_from_string(sc_id, &r_sharemap_get.in.ShadowCopyId);
519         if (!NT_STATUS_IS_OK(status)) {
520                 DEBUG(0, ("Invalid shadow_copy_id parameter\n"));
521                 goto err_out;
522         }
523         r_sharemap_get.in.Level = 1;
524         status = dcerpc_fss_GetShareMapping_r(b, tmp_ctx, &r_sharemap_get);
525         if (!NT_STATUS_IS_OK(status)) {
526                 DEBUG(0, ("GetShareMapping failed\n"));
527                 goto err_out;
528         } else if (r_sharemap_get.out.result != 0) {
529                 DEBUG(0, ("failed GetShareMapping response: 0x%x\n",
530                           r_sharemap_get.out.result));
531                 status = NT_STATUS_UNSUCCESSFUL;
532                 goto err_out;
533         }
534
535         map = r_sharemap_get.out.ShareMapping->ShareMapping1;
536         printf("%s(%s): share %s is a shadow-copy of %s at %s\n",
537                GUID_string(tmp_ctx, &map->ShadowCopySetId),
538                GUID_string(tmp_ctx, &map->ShadowCopyId),
539                map->ShadowCopyShareName, map->ShareNameUNC,
540                nt_time_string(tmp_ctx, map->tstamp));
541
542 err_out:
543         talloc_free(tmp_ctx);
544         return status;
545 }
546
547 static void cmd_fss_recov_complete_usage(const char *script_name)
548 {
549         printf("usage: %s [shadow_copy_set_id]\n", script_name);
550 }
551
552 static NTSTATUS cmd_fss_recov_complete(struct rpc_pipe_client *cli,
553                                        TALLOC_CTX *mem_ctx, int argc,
554                                        const char **argv)
555 {
556         NTSTATUS status;
557         struct fss_RecoveryCompleteShadowCopySet r;
558         struct dcerpc_binding_handle *b = cli->binding_handle;
559         const char *sc_set_id;
560
561         if (argc != 2) {
562                 cmd_fss_recov_complete_usage(argv[0]);
563                 return NT_STATUS_UNSUCCESSFUL;
564         }
565         sc_set_id = argv[1];
566
567         ZERO_STRUCT(r);
568         status = GUID_from_string(sc_set_id, &r.in.ShadowCopySetId);
569         if (!NT_STATUS_IS_OK(status)) {
570                 DEBUG(0, ("Invalid shadow_copy_set_id\n"));
571                 return NT_STATUS_INVALID_PARAMETER;
572         }
573
574         status = dcerpc_fss_RecoveryCompleteShadowCopySet_r(b, mem_ctx, &r);
575         if (!NT_STATUS_IS_OK(status) || (r.out.result != 0)) {
576                 DEBUG(0, ("RecoveryCompleteShadowCopySet failed: %s "
577                           "result: 0x%x\n", nt_errstr(status), r.out.result));
578                 return status;
579         }
580         printf("%s: shadow-copy set marked recovery complete\n", sc_set_id);
581
582         return NT_STATUS_OK;
583 }
584
585 /* List of commands exported by this module */
586 struct cmd_set fss_commands[] = {
587
588         { "FSRVP" },
589
590         {
591                 .name = "fss_is_path_sup",
592                 .returntype = RPC_RTYPE_NTSTATUS,
593                 .ntfn = cmd_fss_is_path_sup,
594                 .table = &ndr_table_FileServerVssAgent,
595                 .rpc_pipe = NULL,
596                 .description = "Check whether a share supports shadow-copy "
597                                "requests",
598                 .usage = "",
599         },
600         {
601                 .name = "fss_get_sup_version",
602                 .returntype = RPC_RTYPE_NTSTATUS,
603                 .ntfn = cmd_fss_get_sup_version,
604                 .table = &ndr_table_FileServerVssAgent,
605                 .rpc_pipe = NULL,
606                 .description = "Get supported FSRVP version from server",
607                 .usage = "",
608         },
609         {
610                 .name = "fss_create_expose",
611                 .returntype = RPC_RTYPE_NTSTATUS,
612                 .ntfn = cmd_fss_create_expose,
613                 .table = &ndr_table_FileServerVssAgent,
614                 .rpc_pipe = NULL,
615                 .description = "Request shadow-copy creation and exposure",
616                 .usage = "",
617         },
618         {
619                 .name = "fss_delete",
620                 .returntype = RPC_RTYPE_NTSTATUS,
621                 .ntfn = cmd_fss_delete,
622                 .table = &ndr_table_FileServerVssAgent,
623                 .rpc_pipe = NULL,
624                 .description = "Request shadow-copy share deletion",
625                 .usage = "",
626         },
627         {
628                 .name = "fss_has_shadow_copy",
629                 .returntype = RPC_RTYPE_NTSTATUS,
630                 .ntfn = cmd_fss_is_shadow_copied,
631                 .table = &ndr_table_FileServerVssAgent,
632                 .rpc_pipe = NULL,
633                 .description = "Check for an associated share shadow-copy",
634                 .usage = "",
635         },
636         {
637                 .name = "fss_get_mapping",
638                 .returntype = RPC_RTYPE_NTSTATUS,
639                 .ntfn = cmd_fss_get_mapping,
640                 .table = &ndr_table_FileServerVssAgent,
641                 .rpc_pipe = NULL,
642                 .description = "Get shadow-copy share mapping information",
643                 .usage = "",
644         },
645         {
646                 .name = "fss_recovery_complete",
647                 .returntype = RPC_RTYPE_NTSTATUS,
648                 .ntfn = cmd_fss_recov_complete,
649                 .table = &ndr_table_FileServerVssAgent,
650                 .rpc_pipe = NULL,
651                 .description = "Flag read-write snapshot as recovery complete, "
652                                "allowing further shadow-copy requests",
653                 .usage = "",
654         },
655         { NULL }
656 };