Line data Source code
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 68 : 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 68 : cmd = lp_parm_const_string(handle->conn->params->service,
41 : "shell_snap", "check path command", "");
42 68 : if ((cmd == NULL) || (strlen(cmd) == 0)) {
43 0 : DEBUG(0,
44 : ("\"shell_snap:check path command\" not configured\n"));
45 0 : status = NT_STATUS_NOT_SUPPORTED;
46 0 : goto err_out;
47 : }
48 :
49 68 : tmp_ctx = talloc_new(mem_ctx);
50 68 : if (tmp_ctx == NULL) {
51 0 : status = NT_STATUS_NO_MEMORY;
52 0 : goto err_out;
53 : }
54 :
55 : /* add service path argument */
56 68 : cmd_run = talloc_asprintf(tmp_ctx, "%s %s", cmd, service_path);
57 68 : if (cmd_run == NULL) {
58 0 : status = NT_STATUS_NO_MEMORY;
59 0 : goto err_tmp_free;
60 : }
61 :
62 68 : ret = smbrun(cmd_run, NULL, NULL);
63 68 : if (ret != 0) {
64 0 : DEBUG(0, ("%s failed with %d\n", cmd_run, ret));
65 0 : status = NT_STATUS_NOT_SUPPORTED;
66 0 : goto err_tmp_free;
67 : }
68 :
69 : /* assume the service path is the base volume */
70 68 : *base_volume = talloc_strdup(mem_ctx, service_path);
71 68 : if (*base_volume == NULL) {
72 0 : status = NT_STATUS_NO_MEMORY;
73 0 : goto err_tmp_free;
74 : }
75 68 : status = NT_STATUS_OK;
76 68 : err_tmp_free:
77 68 : talloc_free(tmp_ctx);
78 68 : err_out:
79 68 : return status;
80 : }
81 :
82 16 : 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 16 : int fd = -1;
95 : TALLOC_CTX *tmp_ctx;
96 : NTSTATUS status;
97 :
98 16 : cmd = lp_parm_const_string(handle->conn->params->service,
99 : "shell_snap", "create command", "");
100 16 : if ((cmd == NULL) || (strlen(cmd) == 0)) {
101 0 : DEBUG(1, ("\"shell_snap:create command\" not configured\n"));
102 0 : status = NT_STATUS_NOT_SUPPORTED;
103 0 : goto err_out;
104 : }
105 :
106 16 : tmp_ctx = talloc_new(mem_ctx);
107 16 : if (tmp_ctx == NULL) {
108 0 : status = NT_STATUS_NO_MEMORY;
109 0 : goto err_out;
110 : }
111 :
112 : /* add base vol argument */
113 16 : cmd_run = talloc_asprintf(tmp_ctx, "%s %s", cmd, base_volume);
114 16 : if (cmd_run == NULL) {
115 0 : status = NT_STATUS_NO_MEMORY;
116 0 : goto err_tmp_free;
117 : }
118 :
119 16 : ret = smbrun(cmd_run, &fd, NULL);
120 16 : talloc_free(cmd_run);
121 16 : if (ret != 0) {
122 0 : if (fd != -1) {
123 0 : close(fd);
124 : }
125 0 : status = NT_STATUS_UNSUCCESSFUL;
126 0 : goto err_tmp_free;
127 : }
128 :
129 16 : numlines = 0;
130 16 : qlines = fd_lines_load(fd, &numlines, PATH_MAX + 1, tmp_ctx);
131 16 : close(fd);
132 :
133 : /* script must return the snapshot path as a single line */
134 16 : if ((numlines == 0) || (qlines == NULL) || (qlines[0] == NULL)) {
135 0 : status = NT_STATUS_UNSUCCESSFUL;
136 0 : goto err_tmp_free;
137 : }
138 :
139 16 : *base_path = talloc_strdup(mem_ctx, base_volume);
140 16 : if (*base_path == NULL) {
141 0 : status = NT_STATUS_NO_MEMORY;
142 0 : goto err_tmp_free;
143 : }
144 16 : *snap_path = talloc_strdup(mem_ctx, qlines[0]);
145 16 : if (*snap_path == NULL) {
146 0 : status = NT_STATUS_NO_MEMORY;
147 0 : talloc_free(*base_path);
148 0 : goto err_tmp_free;
149 : }
150 :
151 16 : status = NT_STATUS_OK;
152 16 : err_tmp_free:
153 16 : talloc_free(tmp_ctx);
154 16 : err_out:
155 16 : return status;
156 : }
157 :
158 10 : 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 10 : cmd = lp_parm_const_string(handle->conn->params->service,
168 : "shell_snap", "delete command", "");
169 10 : if ((cmd == NULL) || (strlen(cmd) == 0)) {
170 0 : DEBUG(1, ("\"shell_snap:delete command\" not configured\n"));
171 0 : return NT_STATUS_NOT_SUPPORTED;
172 : }
173 :
174 : /* add base path and snap path arguments */
175 10 : cmd_run = talloc_asprintf(mem_ctx, "%s %s %s",
176 : cmd, base_path, snap_path);
177 10 : if (cmd_run == NULL) {
178 0 : return NT_STATUS_NO_MEMORY;
179 : }
180 :
181 10 : ret = smbrun(cmd_run, NULL, NULL);
182 10 : talloc_free(cmd_run);
183 10 : if (ret != 0) {
184 0 : return NT_STATUS_UNSUCCESSFUL;
185 : }
186 :
187 10 : 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 : static_decl_vfs;
197 39 : NTSTATUS vfs_shell_snap_init(TALLOC_CTX *ctx)
198 : {
199 39 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
200 : "shell_snap", &shell_snap_fns);
201 : }
|