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