/* Make a media pathname out of a filename which can have embedded strftime() | conversions and up to two pikrellcam filename substitution variables. | Return string is allocated memory. */ char * media_pathname(char *dir, char *fname, char var1, char *arg1, char var2, char *arg2) { char buf[200], *path; /* Do strftime() first to get rid of '%' specifiers in fname. */ buf[0] = '\0'; strftime(buf, sizeof(buf), fname, &pikrellcam.tm_local); asprintf(&path, "%s/%s", dir, buf); /* Now process any $V substitution variables. */ path = substitute_var(path, var1, arg1); path = substitute_var(path, var2, arg2); return path; }
/* exec a command with the given arg. Any strftime() % replacements should | have been done before calling this so there will remain only pikrellcam | specific $X conversions. Change all '$X' to '%s' and printf in what we | want according to X. */ static int exec_command(char *command, char *arg, boolean wait, pid_t *pid) { struct tm *tm_now; CompositeVector *frame_vec = &motion_frame.final_preview_vector; char specifier, *fmt, *fmt_arg, *copy, *cmd_line, *name, buf[BUFSIZ]; int t, i, status = 0; if (!command || !*command) return -1; copy = strdup(command); cmd_line = copy; while ( (fmt = strchr(copy, '$')) != NULL && *(fmt + 1) ) { specifier = *(fmt + 1); *fmt++ = '%'; *fmt = 's'; switch (specifier) { case 'F': fmt_arg = arg ? arg : ""; break; case 'H': fmt_arg = pikrellcam.hostname; break; case 'E': fmt_arg = pikrellcam.effective_user; break; case 'I': fmt_arg = pikrellcam.install_dir; break; case 's': fmt_arg = pikrellcam.still_last; break; case 'S': fmt_arg = pikrellcam.still_dir; break; case 'v': fmt_arg = pikrellcam.video_last; break; case 'V': fmt_arg = pikrellcam.video_dir; break; case 't': fmt_arg = pikrellcam.thumb_dir; break; case 'T': snprintf(buf, sizeof(buf), "%05d", time_lapse.series); name = media_pathname(pikrellcam.video_dir, pikrellcam.timelapse_video_name, 'n', buf, '\0', NULL); snprintf(buf, sizeof(buf), "%s", name); free(name); fmt_arg = buf; dup_string(&pikrellcam.timelapse_video_pending, fmt_arg); break; case 'l': snprintf(buf, sizeof(buf), "%05d", time_lapse.series); name = strdup(pikrellcam.timelapse_format); name = substitute_var(name, 'n', buf); name = substitute_var(name, 'N', "%05d"); snprintf(buf, sizeof(buf), "%s", name); free(name); fmt_arg = buf; break; case 'L': fmt_arg = pikrellcam.timelapse_dir; break; case 'a': fmt_arg = pikrellcam.archive_dir; break; case 'm': fmt_arg = pikrellcam.media_dir; break; case 'M': fmt_arg = pikrellcam.mjpeg_filename; break; case 'P': fmt_arg = pikrellcam.command_fifo; break; case 'C': fmt_arg = pikrellcam.script_dir; break; case 'G': fmt_arg = pikrellcam.log_file; break; case 'N': snprintf(buf, sizeof(buf), "%05d", time_lapse.sequence); fmt_arg = buf; break; case 'n': snprintf(buf, sizeof(buf), "%05d", time_lapse.series); fmt_arg = buf; break; case 'i': /* width of motion area */ t = frame_vec->box_w; snprintf(buf, sizeof(buf), "%d", t); fmt_arg = buf; break; case 'J': /* height of motion area */ t = frame_vec->box_h; snprintf(buf, sizeof(buf), "%d", t); fmt_arg = buf; break; case 'K': /* center X of motion area */ t = frame_vec->x; snprintf(buf, sizeof(buf), "%d", t); fmt_arg = buf; break; case 'Y': /* center Y of motion area */ t = frame_vec->y; snprintf(buf, sizeof(buf), "%d", t); fmt_arg = buf; break; case 'D': /* current_minute dawn sunrise sunset dusk */ tm_now = localtime(&pikrellcam.t_now); snprintf(buf, sizeof(buf), "%d %d %d %d %d", tm_now->tm_hour * 60 + tm_now->tm_min, sun.dawn, sun.sunrise, sun.sunset, sun.dusk); fmt_arg = buf; break; case 'Z': fmt_arg = pikrellcam.version; break; default: fmt_arg = "?"; break; } if (!fmt_arg || !fmt_arg) log_printf(" Bad fmt_arg %p for specifier %c\n", fmt_arg, specifier); asprintf(&cmd_line, copy, fmt_arg); free(copy); copy = cmd_line; } log_printf("execl:[%s]\n", cmd_line); if ((*pid = fork()) == 0) { /* child - execute command in background */ for (i = getdtablesize(); i > 2; --i) close(i); setsid(); /* new session group - ie detach */ execl("/bin/sh", "sh", "-c", cmd_line, " &", NULL); _exit (EXIT_FAILURE); } else if (*pid < 0) { perror("Fork failed."); status = -1; } else if (wait) /* If parent needs to wait */ { if (waitpid (*pid, &status, 0) != *pid) status = -1; } free(cmd_line); return status; }