s3: smbd: Change filename_convert_smb1_search_path() to use extract_snapshot_token().
[Samba.git] / ctdb / common / event_script.c
blobedd607f7a149763061701877ee04a922867bba1c
1 /*
2 Low level event script handling
4 Copyright (C) Amitay Isaacs 2017
5 Copyright (C) Martin Schwenke 2018
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "replace.h"
22 #include "system/filesys.h"
23 #include "system/dir.h"
24 #include "system/glob.h"
26 #include <talloc.h>
28 #include "common/event_script.h"
30 static int script_filter(const struct dirent *de)
32 int ret;
34 /* Match a script pattern */
35 ret = fnmatch("[0-9][0-9].*.script", de->d_name, 0);
36 if (ret == 0) {
37 return 1;
40 return 0;
43 int event_script_get_list(TALLOC_CTX *mem_ctx,
44 const char *script_dir,
45 struct event_script_list **out)
47 struct dirent **namelist = NULL;
48 struct event_script_list *script_list = NULL;
49 size_t ds_len;
50 int count, ret;
51 int i;
53 count = scandir(script_dir, &namelist, script_filter, alphasort);
54 if (count == -1) {
55 ret = errno;
56 goto done;
59 script_list = talloc_zero(mem_ctx, struct event_script_list);
60 if (script_list == NULL) {
61 goto nomem;
64 if (count == 0) {
65 ret = 0;
66 *out = script_list;
67 goto done;
70 script_list->num_scripts = count;
71 script_list->script = talloc_zero_array(script_list,
72 struct event_script *,
73 count);
74 if (script_list->script == NULL) {
75 goto nomem;
78 ds_len = strlen(".script");
79 for (i = 0; i < count; i++) {
80 struct event_script *s;
81 struct stat statbuf;
83 s = talloc_zero(script_list->script, struct event_script);
84 if (s == NULL) {
85 goto nomem;
88 script_list->script[i] = s;
90 s->name = talloc_strndup(script_list->script,
91 namelist[i]->d_name,
92 strlen(namelist[i]->d_name) - ds_len);
93 if (s->name == NULL) {
94 goto nomem;
97 s->path = talloc_asprintf(script_list->script,
98 "%s/%s",
99 script_dir,
100 namelist[i]->d_name);
101 if (s->path == NULL) {
102 goto nomem;
105 ret = stat(s->path, &statbuf);
106 if (ret == 0) {
108 * If ret != 0 this is either a dangling
109 * symlink or it has just disappeared. Either
110 * way, it isn't executable. See the note
111 * below about things that have disappeared.
113 if (statbuf.st_mode & S_IXUSR) {
114 s->enabled = true;
119 *out = script_list;
120 ret = 0;
121 goto done;
123 nomem:
124 ret = ENOMEM;
125 talloc_free(script_list);
127 done:
128 if (namelist != NULL && count != -1) {
129 for (i=0; i<count; i++) {
130 free(namelist[i]);
132 free(namelist);
135 return ret;
138 int event_script_chmod(const char *script_dir,
139 const char *script_name,
140 bool enable)
142 const char *dot_script = ".script";
143 size_t ds_len = strlen(dot_script);
144 size_t sn_len = strlen(script_name);
145 DIR *dirp;
146 struct dirent *de;
147 char buf[PATH_MAX];
148 const char *script_file;
149 int ret, new_mode;
150 char filename[PATH_MAX];
151 struct stat st;
152 bool found;
153 ino_t found_inode;
154 int fd = -1;
156 /* Allow script_name to already have ".script" suffix */
157 if (sn_len > ds_len &&
158 strcmp(&script_name[sn_len - ds_len], dot_script) == 0) {
159 script_file = script_name;
160 } else {
161 ret = snprintf(buf, sizeof(buf), "%s.script", script_name);
162 if (ret < 0 || (size_t)ret >= sizeof(buf)) {
163 return ENAMETOOLONG;
165 script_file = buf;
168 dirp = opendir(script_dir);
169 if (dirp == NULL) {
170 return errno;
173 found = false;
174 while ((de = readdir(dirp)) != NULL) {
175 if (strcmp(de->d_name, script_file) == 0) {
176 /* check for valid script names */
177 ret = script_filter(de);
178 if (ret == 0) {
179 closedir(dirp);
180 return EINVAL;
183 found = true;
184 found_inode = de->d_ino;
185 break;
188 closedir(dirp);
190 if (! found) {
191 return ENOENT;
194 ret = snprintf(filename,
195 sizeof(filename),
196 "%s/%s",
197 script_dir,
198 script_file);
199 if (ret < 0 || (size_t)ret >= sizeof(filename)) {
200 return ENAMETOOLONG;
203 fd = open(filename, O_RDWR);
204 if (fd == -1) {
205 ret = errno;
206 goto done;
209 ret = fstat(fd, &st);
210 if (ret != 0) {
211 ret = errno;
212 goto done;
216 * If the directory entry inode number doesn't match the one
217 * returned by fstat() then this is probably a symlink, so the
218 * caller should not be calling this function. Note that this
219 * is a cheap sanity check to catch most programming errors.
220 * This doesn't cost any extra system calls but can still miss
221 * the unlikely case where the symlink is to a file on a
222 * different filesystem with the same inode number as the
223 * symlink.
225 if (found && found_inode != st.st_ino) {
226 ret = EINVAL;
227 goto done;
230 if (enable) {
231 new_mode = st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH);
232 } else {
233 new_mode = st.st_mode & ~(S_IXUSR | S_IXGRP | S_IXOTH);
236 ret = fchmod(fd, new_mode);
237 if (ret != 0) {
238 ret = errno;
239 goto done;
242 done:
243 if (fd != -1) {
244 close(fd);
246 return ret;