summaryrefslogtreecommitdiff
path: root/snac.c
diff options
context:
space:
mode:
Diffstat (limited to 'snac.c')
-rw-r--r--snac.c158
1 files changed, 99 insertions, 59 deletions
diff --git a/snac.c b/snac.c
index edf0a1e..9c84205 100644
--- a/snac.c
+++ b/snac.c
@@ -35,7 +35,9 @@
35#include <sys/stat.h> 35#include <sys/stat.h>
36#include <sys/wait.h> 36#include <sys/wait.h>
37#include <limits.h> 37#include <limits.h>
38#include <stdio.h>
38#include <stdlib.h> 39#include <stdlib.h>
40#include <unistd.h>
39 41
40xs_str *srv_basedir = NULL; 42xs_str *srv_basedir = NULL;
41xs_dict *srv_config = NULL; 43xs_dict *srv_config = NULL;
@@ -177,6 +179,46 @@ int check_password(const char *uid, const char *passwd, const char *hash)
177} 179}
178 180
179 181
182char* findprog(const char *prog)
183/* find a prog in PATH and return the first match */
184{
185 char *path_env, *path, *dir, filename[PATH_MAX];
186 int len;
187 struct stat sbuf;
188
189 path_env = getenv("PATH");
190 if (!prog || !path_env)
191 return NULL;
192
193 path_env = strdup(path_env);
194 if (!path_env)
195 return NULL;
196 path = path_env;
197
198 while ((dir = strsep(&path, ":")) != NULL) {
199 /* empty entries as ./ instead of / */
200 if (*dir == '\0')
201 dir = ".";
202
203 /* strip trailing / */
204 len = strlen(dir);
205 while (len > 0 && dir[len-1] == '/')
206 dir[--len] = '\0';
207
208 len = snprintf(filename, sizeof(filename), "%s/%s", dir, prog);
209 if (len > 0 && len < (int) sizeof(filename) &&
210 (stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
211 access(filename, X_OK) == 0) {
212 free(path_env);
213 return strdup(filename);
214 }
215 }
216
217 free(path_env);
218 return NULL;
219}
220
221
180int strip_media(const char *fn) 222int strip_media(const char *fn)
181/* strips EXIF data from a file */ 223/* strips EXIF data from a file */
182{ 224{
@@ -207,23 +249,24 @@ int strip_media(const char *fn)
207 xs_endswith(l_fn, ".gif") || xs_endswith(l_fn, ".bmp")) { 249 xs_endswith(l_fn, ".gif") || xs_endswith(l_fn, ".bmp")) {
208 250
209 const char *mp = xs_dict_get(srv_config, "mogrify_path"); 251 const char *mp = xs_dict_get(srv_config, "mogrify_path");
210 if (mp == NULL)
211 mp = "mogrify";
212 252
213 xs *cmd = xs_fmt("cd \"%s\" && %s -auto-orient -strip \"%s\" 2>/dev/null", srv_basedir, mp, r_fn); 253 pid_t pid = fork();
214 254 if (pid == -1) {
215 ret = system(cmd); 255 srv_log(xs_fmt("strip_media: cannot fork()"));
256 return -1;
257 } else if (pid == 0) {
258 chdir(srv_basedir);
259 execl(mp, "-auto-orient", "-strip", r_fn, (char*) NULL);
260 _exit(1);
261 }
216 262
217 if (ret != 0) { 263 if (waitpid(pid, &ret, 0) == -1) {
218 int code = 0; 264 srv_log(xs_fmt("strip_media: cannot waitpid()"));
219 if (WIFEXITED(ret)) 265 return -1;
220 code = WEXITSTATUS(ret);
221
222 if (code == 127)
223 srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'mogrify_path' in server.json.", r_fn, mp));
224 else
225 srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
226 } 266 }
267
268 if (ret != 0)
269 srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
227 else 270 else
228 srv_debug(1, xs_fmt("strip_media: stripped %s", r_fn)); 271 srv_debug(1, xs_fmt("strip_media: stripped %s", r_fn));
229 } 272 }
@@ -234,35 +277,33 @@ int strip_media(const char *fn)
234 xs_endswith(l_fn, ".mkv") || xs_endswith(l_fn, ".avi")) { 277 xs_endswith(l_fn, ".mkv") || xs_endswith(l_fn, ".avi")) {
235 278
236 const char *fp = xs_dict_get(srv_config, "ffmpeg_path"); 279 const char *fp = xs_dict_get(srv_config, "ffmpeg_path");
237 if (fp == NULL)
238 fp = "ffmpeg";
239 280
240 /* ffmpeg cannot modify in-place, so we need a temp file */ 281 /* ffmpeg cannot modify in-place, so we need a temp file */
241 /* we must preserve valid extension for ffmpeg to guess the format */ 282 /* we must preserve valid extension for ffmpeg to guess the format */
242 const char *ext = strrchr(r_fn, '.'); 283 const char *ext = strrchr(r_fn, '.');
243 if (ext == NULL) ext = ""; 284 if (ext == NULL) ext = "";
244 xs *tmp_fn = xs_fmt("%s.tmp%s", r_fn, ext); 285 xs *tmp_fn = xs_fmt("%s.tmp%s", r_fn, ext);
245
246 /* -map_metadata -1 strips all global metadata */
247 /* -c copy copies input streams without re-encoding */
248 /* we don't silence stderr so we can debug issues */
249 /* we explicitly cd to srv_basedir to ensure relative paths work */
250 xs *cmd = xs_fmt("cd \"%s\" && %s -y -i \"%s\" -map_metadata -1 -c copy \"%s\"", srv_basedir, fp, r_fn, tmp_fn);
251 286
252 ret = system(cmd); 287 pid_t pid = fork();
288 if (pid == -1) {
289 srv_log(xs_fmt("strip_media: cannot fork()"));
290 return -1;
291 } else if (pid == 0) {
292 chdir(srv_basedir);
293 /* -map_metadata -1 strips all global metadata */
294 /* -c copy copies input streams without re-encoding */
295 execl(fp, "-y", "-i", r_fn, "-map_metadata", "-1", "-c", "copy", tmp_fn, (char*) NULL);
296 _exit(1);
297 }
298
299 if (waitpid(pid, &ret, 0) == -1) {
300 srv_log(xs_fmt("strip_media: cannot waitpid()"));
301 return -1;
302 }
253 303
254 if (ret != 0) { 304 if (ret != 0) {
255 int code = 0; 305 srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
256 if (WIFEXITED(ret)) 306
257 code = WEXITSTATUS(ret);
258
259 if (code == 127)
260 srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'ffmpeg_path' in server.json.", r_fn, fp));
261 else {
262 srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
263 srv_log(xs_fmt("strip_media: command was: %s", cmd));
264 }
265
266 /* try to cleanup, just in case */ 307 /* try to cleanup, just in case */
267 /* unlink needs full path too if we are not in basedir */ 308 /* unlink needs full path too if we are not in basedir */
268 xs *full_tmp_fn = xs_fmt("%s/%s", srv_basedir, tmp_fn); 309 xs *full_tmp_fn = xs_fmt("%s/%s", srv_basedir, tmp_fn);
@@ -286,38 +327,37 @@ int strip_media(const char *fn)
286 327
287 328
288int check_strip_tool(void) 329int check_strip_tool(void)
330/* check if strip_exif tools do exist and fix their absolute path */
289{ 331{
290 const xs_val *v = xs_dict_get(srv_config, "strip_exif"); 332 const xs_val *v = xs_dict_get(srv_config, "strip_exif");
333 /* skip if unless strip_exif; return non-error */
334 if (xs_type(v) != XSTYPE_TRUE)
335 return 1;
336
291 int ret = 1; 337 int ret = 1;
338 const char *progs[] = { "ffmpeg", "mogrify" };
292 339
293 if (xs_type(v) == XSTYPE_TRUE) { 340 for (int i = 0; i < (int)(sizeof(progs) / sizeof(progs[0])); i++) {
294 /* check mogrify */ 341 xs_str *key = xs_fmt("%s_path", progs[i]);
295 { 342
296 const char *mp = xs_dict_get(srv_config, "mogrify_path"); 343 const char *val = xs_dict_get(srv_config, key);
297 if (mp == NULL) 344 if (val == NULL) {
298 mp = "mogrify"; 345 val = findprog(progs[i]);
299 346 if (val != NULL)
300 xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", mp); 347 srv_debug(1, xs_fmt("check_strip_tool: found %s in PATH at %s", progs[i], val));
301
302 if (system(cmd) != 0) {
303 srv_log(xs_fmt("check_strip_tool: '%s' not working", mp));
304 ret = 0;
305 }
306 } 348 }
307 349
308 /* check ffmpeg */ 350 if (val == NULL) {
309 if (ret) { 351 srv_log(xs_fmt("check_strip_tool: %s not found in PATH", progs[i]));
310 const char *fp = xs_dict_get(srv_config, "ffmpeg_path"); 352 ret = 0;
311 if (fp == NULL) 353 } else if (access(val, X_OK) != 0) {
312 fp = "ffmpeg"; 354 srv_log(xs_fmt("check_strip_tool: %s '%s' is not executable", progs[i], val));
313 355 ret = 0;
314 xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", fp); 356 } else {
315 357 srv_config = xs_dict_set(srv_config, key, val);
316 if (system(cmd) != 0) {
317 srv_log(xs_fmt("check_strip_tool: '%s' not working", fp));
318 ret = 0;
319 }
320 } 358 }
359
360 xs_free(key);
321 } 361 }
322 362
323 return ret; 363 return ret;