lib: modules: Change XXX_init interface from XXX_init(void) to XXX_init(TALLOC_CTX *)
[nivanova/samba-autobuild/.git] / source3 / modules / vfs_shell_snap.c
1 /*
2  * Module for snapshot management using shell callouts
3  *
4  * Copyright (C) David Disseldorp 2013-2015
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "include/ntioctl.h"
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24
25 /*
26  * Check whether a path can be shadow copied. Return the base volume, allowing
27  * the caller to determine if multiple paths lie on the same base volume.
28  */
29 static NTSTATUS shell_snap_check_path(struct vfs_handle_struct *handle,
30                                       TALLOC_CTX *mem_ctx,
31                                       const char *service_path,
32                                       char **base_volume)
33 {
34         NTSTATUS status;
35         const char *cmd;
36         char *cmd_run;
37         int ret;
38         TALLOC_CTX *tmp_ctx;
39
40         cmd = lp_parm_const_string(handle->conn->params->service,
41                                    "shell_snap", "check path command", "");
42         if ((cmd == NULL) || (strlen(cmd) == 0)) {
43                 DEBUG(0,
44                       ("\"shell_snap:check path command\" not configured\n"));
45                 status = NT_STATUS_NOT_SUPPORTED;
46                 goto err_out;
47         }
48
49         tmp_ctx = talloc_new(mem_ctx);
50         if (tmp_ctx == NULL) {
51                 status = NT_STATUS_NO_MEMORY;
52                 goto err_out;
53         }
54
55         /* add service path argument */
56         cmd_run = talloc_asprintf(tmp_ctx, "%s %s", cmd, service_path);
57         if (cmd_run == NULL) {
58                 status = NT_STATUS_NO_MEMORY;
59                 goto err_tmp_free;
60         }
61
62         ret = smbrun(cmd_run, NULL, NULL);
63         if (ret != 0) {
64                 DEBUG(0, ("%s failed with %d\n", cmd_run, ret));
65                 status = NT_STATUS_NOT_SUPPORTED;
66                 goto err_tmp_free;
67         }
68
69         /* assume the service path is the base volume */
70         *base_volume = talloc_strdup(mem_ctx, service_path);
71         if (*base_volume == NULL) {
72                 status = NT_STATUS_NO_MEMORY;
73                 goto err_tmp_free;
74         }
75         status = NT_STATUS_OK;
76 err_tmp_free:
77         talloc_free(tmp_ctx);
78 err_out:
79         return status;
80 }
81
82 static NTSTATUS shell_snap_create(struct vfs_handle_struct *handle,
83                                   TALLOC_CTX *mem_ctx,
84                                   const char *base_volume,
85                                   time_t *tstamp,
86                                   bool rw,
87                                   char **base_path,
88                                   char **snap_path)
89 {
90         const char *cmd;
91         char *cmd_run;
92         char **qlines;
93         int numlines, ret;
94         int fd = -1;
95         TALLOC_CTX *tmp_ctx;
96         NTSTATUS status;
97
98         cmd = lp_parm_const_string(handle->conn->params->service,
99                                    "shell_snap", "create command", "");
100         if ((cmd == NULL) || (strlen(cmd) == 0)) {
101                 DEBUG(1, ("\"shell_snap:create command\" not configured\n"));
102                 status = NT_STATUS_NOT_SUPPORTED;
103                 goto err_out;
104         }
105
106         tmp_ctx = talloc_new(mem_ctx);
107         if (tmp_ctx == NULL) {
108                 status = NT_STATUS_NO_MEMORY;
109                 goto err_out;
110         }
111
112         /* add base vol argument */
113         cmd_run = talloc_asprintf(tmp_ctx, "%s %s", cmd, base_volume);
114         if (cmd_run == NULL) {
115                 status = NT_STATUS_NO_MEMORY;
116                 goto err_tmp_free;
117         }
118
119         ret = smbrun(cmd_run, &fd, NULL);
120         talloc_free(cmd_run);
121         if (ret != 0) {
122                 if (fd != -1) {
123                         close(fd);
124                 }
125                 status = NT_STATUS_UNSUCCESSFUL;
126                 goto err_tmp_free;
127         }
128
129         numlines = 0;
130         qlines = fd_lines_load(fd, &numlines, PATH_MAX + 1, tmp_ctx);
131         close(fd);
132
133         /* script must return the snapshot path as a single line */
134         if ((numlines == 0) || (qlines == NULL) || (qlines[0] == NULL)) {
135                 status = NT_STATUS_UNSUCCESSFUL;
136                 goto err_tmp_free;
137         }
138
139         *base_path = talloc_strdup(mem_ctx, base_volume);
140         if (*base_path == NULL) {
141                 status = NT_STATUS_NO_MEMORY;
142                 goto err_tmp_free;
143         }
144         *snap_path = talloc_strdup(mem_ctx, qlines[0]);
145         if (*snap_path == NULL) {
146                 status = NT_STATUS_NO_MEMORY;
147                 talloc_free(*base_path);
148                 goto err_tmp_free;
149         }
150
151         status = NT_STATUS_OK;
152 err_tmp_free:
153         talloc_free(tmp_ctx);
154 err_out:
155         return status;
156 }
157
158 static NTSTATUS shell_snap_delete(struct vfs_handle_struct *handle,
159                                   TALLOC_CTX *mem_ctx,
160                                   char *base_path,
161                                   char *snap_path)
162 {
163         const char *cmd;
164         char *cmd_run;
165         int ret;
166
167         cmd = lp_parm_const_string(handle->conn->params->service,
168                                    "shell_snap", "delete command", "");
169         if ((cmd == NULL) || (strlen(cmd) == 0)) {
170                 DEBUG(1, ("\"shell_snap:delete command\" not configured\n"));
171                 return NT_STATUS_NOT_SUPPORTED;
172         }
173
174         /* add base path and snap path arguments */
175         cmd_run = talloc_asprintf(mem_ctx, "%s %s %s",
176                                   cmd, base_path, snap_path);
177         if (cmd_run == NULL) {
178                 return NT_STATUS_NO_MEMORY;
179         }
180
181         ret = smbrun(cmd_run, NULL, NULL);
182         talloc_free(cmd_run);
183         if (ret != 0) {
184                 return NT_STATUS_UNSUCCESSFUL;
185         }
186
187         return NT_STATUS_OK;
188 }
189
190 static struct vfs_fn_pointers shell_snap_fns = {
191         .snap_check_path_fn = shell_snap_check_path,
192         .snap_create_fn = shell_snap_create,
193         .snap_delete_fn = shell_snap_delete,
194 };
195
196 NTSTATUS vfs_shell_snap_init(TALLOC_CTX *);
197 NTSTATUS vfs_shell_snap_init(TALLOC_CTX *ctx)
198 {
199         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
200                                 "shell_snap", &shell_snap_fns);
201 }