/* handling for child and subprocesses Written by Matthias Hensler Copyright WSPse 1999+2000 eMail: wsp@gmx.de Created: 1999/06/19 Updated: 2000/07/26 */ /* Copying: This program is free software; you can redistribute it and/or modify it under the terms of the GNU Gerneral Public License as published by the Free Soft- ware Foundation; either version 2 of License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "mp3creat.h" #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif /* Externals */ extern void wuuush(int); extern WINDOW *c_newwin(int h, int l, int y, int x, void *proc, int arg1, int arg2); extern int set_active_win(WINDOW *win); extern void c_delwin(WINDOW *win); extern void setup_stat_win(int max_length); extern void print_stat_win(char *text); extern void destroy_stat_win(); extern void store_win_poi(WINDOW *win, void *pointer); extern void *pop_win_poi(WINDOW *win); extern BOOL select_yesno_box(char *tx); extern char *build_mp3_filenm(song_typ *track); extern char *create_sub_string(song_typ *track, int mode); extern char **build_arg_tree(const char *line); extern void free_char_array(char **array); extern void popup_error_win(char *tx); extern void win_effect(WINDOW *win, BOOL e_refresh, BOOL save_coor); extern char *build_mp3_filenm(song_typ *track); extern BOOL select_yesno_box(char *tx); extern int create_sub_dirs(char *filename, BOOL mode); extern char *return_track_tmpname(song_typ *track); extern void is_stat(WINDOW *win, int ys, int ye, int x, int abs, int tot); extern char config_fancy_colors; extern char *def_mp3_dir; extern char *def_mp3_info; extern char *def_cd_rip_nf; extern char *def_cd_rip_of; extern char *def_mp3_enc_nf; extern char *def_mp3_enc_of; extern int of_fifo_buf; /* Globals */ BOOL str_path_check(char *program); WINDOW *proc_out_win; char **proc_stat; int proc_line, proc_pos, proc_outl, proc_reserv; BOOL proc_scroll; pid_t proc_child1, proc_child2; int proc_stdin1, proc_stdout1, proc_stderr1; int proc_stdin2, proc_stdout2, proc_stderr2; char *proc_sub = NULL; char *proc_fifo; int proc_fifo_in, proc_fifo_out; int fifo_for_maxx; void proc_win_linstat(WINDOW *win) { int maxy, maxx; int i,j; int line, x; if((! proc_stat) || (proc_outl > proc_reserv-1)) return; getmaxyx(win, maxy, maxx); is_stat(win, 3, maxy-2, maxx-1, proc_outl, proc_reserv-1); fifo_for_maxx = maxx; line = 3; wmove(win, 3, 1); whline(win, ' ', maxx-2); j = 0; i = proc_outl; proc_scroll = FALSE; while(1) { if(! proc_stat[i]) { wrefresh(win); return; } for(x=1;x>1, maxx); mvwin(win, maxy>>2, 0); wbkgd(win, COLOR_PAIR(1) | A_BOLD); wclear(win); box(win,0,0); mvwaddch(win, 2, 0, ACS_LTEE); whline(win, ACS_HLINE, maxx-2); mvwaddch(win, 2, maxx-1, ACS_RTEE); tx = pop_win_poi(win); if(tx) { x = (maxx - strlen(tx))>>1; if(x < 1) x = 1; mvwaddnstr(win, 1, x, tx, maxx-2); } x = maxx-(strlen(_("F10 to cancel"))+1); if(x < 1) x = 1; mvwaddnstr(win, (maxy>>1)-1, x, _("F10 to cancel"), maxx-2); proc_outl = 0; while(1) { proc_win_linstat(win); if(proc_scroll) proc_outl++; else break; } curs_set(0); } void open_process_win(char *tx) { int maxy, maxx; proc_stat = (char **) malloc(sizeof(char *)); if(! proc_stat) { perror("malloc"); wuuush(1); } proc_stat[0] = NULL; proc_line = 0; proc_outl = 0; proc_pos = 0; proc_reserv = 1; proc_scroll = FALSE; getmaxyx(stdscr, maxy, maxx); fifo_for_maxx = maxx; proc_out_win = c_newwin(maxy>>1, maxx, maxy>>2, 0, proc_win_rebuild, 0, 0); store_win_poi(proc_out_win, tx); proc_win_rebuild(proc_out_win, 0, 0); } void del_process_win() { c_delwin(proc_out_win); free_char_array(proc_stat); } void proc_add_fd(int fd) { char buf; char *poi; int len; int pos; int bytes; len = 0; pos = 0; poi = NULL; while(1) { if(read(fd, &buf, 1) != 1) break; if(buf) { if((buf == '\n') || (buf == '\r')) { if(proc_reserv <= proc_line+1) { proc_reserv = proc_line+2; proc_stat = (char **) realloc(proc_stat, sizeof(char *) * proc_reserv); if(! proc_stat) { perror("realloc"); wuuush(1); } proc_stat[proc_reserv-1] = NULL; } bytes = proc_pos + pos + 1; proc_stat[proc_line] = (char *) realloc(proc_stat[proc_line], sizeof(char) * bytes); if(! proc_stat[proc_line]) { perror("realloc"); wuuush(1); } if(pos) memcpy((proc_stat[proc_line] + proc_pos), poi, pos); *(proc_stat[proc_line] + (bytes-1)) = 0; proc_pos = 0; pos = 0; if(buf == '\n') { proc_line++; proc_win_linstat(proc_out_win); if(proc_scroll) { proc_outl++; proc_win_linstat(proc_out_win); } if(proc_reserv <= proc_line+1) { proc_reserv = proc_line+2; proc_stat = (char **) realloc(proc_stat, sizeof(char *) * proc_reserv); if(! proc_stat) { perror("realloc"); wuuush(1); } proc_stat[proc_reserv-1] = NULL; } } } else if(isprint(buf)) { if(pos >= len-1) { len += 128; poi = (char *) realloc(poi, sizeof(char) * len); if(!poi) { perror("realloc"); wuuush(1); } } *(poi + pos) = buf; pos++; } } } if(pos) { if(proc_reserv <= proc_line+1) { proc_reserv = proc_line+2; proc_stat = (char **) realloc(proc_stat, sizeof(char *) * proc_reserv); if(! proc_stat) { perror("realloc"); wuuush(1); } proc_stat[proc_reserv-1] = NULL; } bytes = proc_pos + pos + 1; proc_stat[proc_line] = (char *) realloc(proc_stat[proc_line], sizeof(char) * bytes); if(! proc_stat[proc_line]) { perror("realloc"); wuuush(1); } memcpy((proc_stat[proc_line] + proc_pos), poi, pos); *(proc_stat[proc_line] + (bytes-1)) = 0; proc_pos = bytes-1; } if(poi) free(poi); } int evaluate_proc(int fd1, int fd2, int fd3, BOOL flag, BOOL emergency) { int inp_ch; BOOL break_out; if(fd1 != -1) proc_add_fd(fd1); if(fd2 != -1) proc_add_fd(fd2); if(fd3 != -1) proc_add_fd(fd3); proc_win_linstat(proc_out_win); cbreak(); noecho(); keypad(proc_out_win, TRUE); if(flag) nodelay(proc_out_win, TRUE); else halfdelay(2); while(1) { break_out = TRUE; if(config_fancy_colors && (!flag)) win_effect(proc_out_win, TRUE, FALSE); inp_ch = wgetch(proc_out_win); switch(inp_ch) { case KEY_F(10): case '0': return 1; break; case ' ': set_active_win(proc_out_win); break_out = FALSE; break; case KEY_UP: if(proc_outl) { proc_outl--; proc_win_linstat(proc_out_win); } break_out = FALSE; break; case KEY_DOWN: if(proc_scroll) { proc_outl++; proc_win_linstat(proc_out_win); } break_out = FALSE; break; case KEY_ENTER: case '\r': case '\n': case KEY_F(12): case '\'': case 'Q': case 'q': case ' ': case 27: if(emergency) { return 1; } break; } if(break_out) break; } return 0; } void shell_change_proc_title(char *tx) { store_win_poi(proc_out_win, tx); set_active_win(proc_out_win); } void shell_wait_for_close_proc(int fd1, int fd2, int fd3) { shell_change_proc_title(_("Failure: read error message before exit")); while(! evaluate_proc(fd1, fd2, fd3, FALSE, TRUE)) { usleep(50000); } } int rip_non_fly(song_typ *track) { int new_pipe1[2]; int new_pipe2[2]; char *cmd_line; char **cmd_args; int status; char *filenm; char *tmp_file; tmp_file = return_track_tmpname(track); if(create_sub_dirs(tmp_file, TRUE)) return 1; if(access(tmp_file, F_OK) == 0) { if(access(tmp_file, W_OK) != 0) { popup_error_win(_("tempfile not writable")); return 1; } if(unlink(tmp_file) != 0) { popup_error_win(_("could not delete tempfile")); return 1; } } filenm = build_mp3_filenm(track); if(create_sub_dirs(filenm, TRUE)) return 1; if(access(filenm, F_OK) == 0) { /* mp3 file already exists */ if(access(filenm, W_OK) != 0) { /* but could not overwritten */ popup_error_win(_("mp3-file already exists and isn't writable")); return 1; } /* ask if it is allowed to overwrite */ cmd_line = (char *) malloc(sizeof(char) * (strlen(filenm)+40)); if(cmd_line == NULL) { perror("malloc"); wuuush(1); } sprintf(cmd_line, _("overwrite \"%s\"?"), filenm); if(! select_yesno_box(cmd_line)) { free(cmd_line); return 2; } free(cmd_line); } /* check for ripper-program */ if(! str_path_check(def_cd_rip_nf)) { popup_error_win(_("couldnīt rip, no prg in $PATH")); return 1; } if(pipe(new_pipe1) != 0) { popup_error_win(_("error opening pipe for STDOUT")); return 1; } if(pipe(new_pipe2) != 0) { popup_error_win(_("error opening pipe for STDERR")); return 1; } proc_stdout1 = new_pipe1[0]; proc_stderr1 = new_pipe2[0]; proc_child1 = fork(); if(proc_child1 == -1) { popup_error_win(_("forking failed")); return 1; } if(proc_child1 == 0) { if(dup2(new_pipe1[1], STDOUT_FILENO) == -1) { exit(EXIT_FAILURE); } if(dup2(new_pipe2[1], STDERR_FILENO) == -1) { exit(EXIT_FAILURE); } close(new_pipe1[0]); close(new_pipe2[0]); /* OK, this is a hack, but create_sub_string cannot determine which name our tempfile has I repair this here. Think: we are using not shared memory, and this child process got his own memory for this file, so nothing could happen! */ cmd_line = create_sub_string(track, 3); /* nonfly ripping */ if(! cmd_line) { exit(EXIT_FAILURE); } cmd_args = build_arg_tree(cmd_line); if(! cmd_args) { exit(EXIT_FAILURE); } execvp(cmd_args[0], cmd_args); exit(EXIT_FAILURE); } /* child started */ fcntl(proc_stdout1, F_SETFL, O_NONBLOCK); close(new_pipe1[1]); /* I won't write to this pipe */ fcntl(proc_stderr1, F_SETFL, O_NONBLOCK); close(new_pipe2[1]); proc_sub = (char *) malloc(sizeof(char) * 50); if(! proc_sub) { perror("malloc"); wuuush(1); } sprintf(proc_sub, _("ripping track %d..."), (track->toc)+1); open_process_win(proc_sub); while(1) { if(waitpid(proc_child1, &status, WNOHANG) == proc_child1) break; if(evaluate_proc(proc_stdout1, proc_stderr1, -1, FALSE, FALSE)) { status = 65530; break; } } /* Terminate */ if(status != 65530 && WEXITSTATUS(status) != EXIT_SUCCESS) { /* give the user the chance to read any failure notice */ shell_wait_for_close_proc(proc_stdout1, proc_stderr1, -1); } free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); if(status == 65530) { kill(proc_child1, SIGINT); popup_error_win(_("action was canceled")); unlink(tmp_file); kill(proc_child1, SIGKILL); return 1; } if(WEXITSTATUS(status) == EXIT_SUCCESS) return 0; popup_error_win(_("child (cd-ripper) died unexpected")); unlink(tmp_file); return 1; } int enc_non_fly(song_typ *track, BOOL del_tmp_file) { int new_pipe1[2]; int new_pipe2[2]; char *cmd_line; char **cmd_args; int status; char *tmp_file; char *filenm; tmp_file = return_track_tmpname(track); if(access(tmp_file, F_OK) != 0) { popup_error_win(_("tempfile not found")); return 1; } if(access(tmp_file, R_OK) != 0) { popup_error_win(_("tempfile not readable")); return 1; } filenm = build_mp3_filenm(track); if(create_sub_dirs(filenm, TRUE)) return 1; if(access(filenm, F_OK) == 0) { /* mp3 file already exists */ if(access(filenm, W_OK) != 0) { /* but could not overwritten */ popup_error_win(_("mp3-file already exists and isn't writable")); return 1; } /* ask if it is allowed to overwrite */ cmd_line = (char *) malloc(sizeof(char) * (strlen(filenm)+40)); if(cmd_line == NULL) { perror("malloc"); wuuush(1); } sprintf(cmd_line, _("overwrite \"%s\"?"), filenm); if(! select_yesno_box(cmd_line)) { free(cmd_line); return 2; } free(cmd_line); } if(! str_path_check(def_mp3_enc_nf)) { popup_error_win(_("couldnīt encode, no prg in $PATH")); return 1; } if(pipe(new_pipe1) != 0) { popup_error_win(_("error opening pipe for STDOUT")); return 1; } if(pipe(new_pipe2) != 0) { popup_error_win(_("error opening pipe for STDERR")); return 1; } proc_stdout1 = new_pipe1[0]; proc_stderr1 = new_pipe2[0]; proc_child1 = fork(); if(proc_child1 == -1) { popup_error_win(_("forking failed")); return 1; } if(proc_child1 == 0) { if(dup2(new_pipe1[1], STDOUT_FILENO) == -1) { exit(EXIT_FAILURE); } if(dup2(new_pipe2[1], STDERR_FILENO) == -1) { exit(EXIT_FAILURE); } close(proc_stdout1); close(proc_stderr1); cmd_line = create_sub_string(track, 1); /* nonfly encoding */ if(! cmd_line) { exit(EXIT_FAILURE); } cmd_args = build_arg_tree(cmd_line); if(! cmd_args) { exit(EXIT_FAILURE); } execvp(cmd_args[0], cmd_args); exit(EXIT_FAILURE); } /* child started */ fcntl(proc_stdout1, F_SETFL, O_NONBLOCK); close(new_pipe1[1]); fcntl(proc_stderr1, F_SETFL, O_NONBLOCK); close(new_pipe2[1]); proc_sub = (char *) malloc(sizeof(char) * 50); if(! proc_sub) { perror("malloc"); wuuush(1); } sprintf(proc_sub, _("encoding track %d..."), (track->toc)+1); open_process_win(proc_sub); while(1) { if(waitpid(proc_child1, &status, WNOHANG) == proc_child1) break; if(evaluate_proc(proc_stdout1, proc_stderr1, -1, FALSE, FALSE)) { status = 65530; break; } } /* Terminate */ if(status != 65530 && WEXITSTATUS(status) != EXIT_SUCCESS) { /* give the user the chance to read any failure notice */ shell_wait_for_close_proc(proc_stdout1, proc_stderr1, -1); } free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); if(status == 65530) { kill(proc_child1, SIGINT); popup_error_win(_("action was canceled")); kill(proc_child1, SIGKILL); return 1; } if(WEXITSTATUS(status) == EXIT_SUCCESS) { if(del_tmp_file) unlink(tmp_file); return 0; } popup_error_win(_("child (encoder) died unexpected")); return 1; } int put_fifo(int fd) { char buf[16384]; int bytes; int fifo_size; fifo_size = of_fifo_buf * 1024; if(proc_fifo_in == proc_fifo_out) bytes = fifo_size; else if(proc_fifo_in > proc_fifo_out) bytes = fifo_size - proc_fifo_in + proc_fifo_out; else bytes = proc_fifo_out - proc_fifo_in; if(bytes < 16390) return 0; sprintf(buf, _("FIFO: %3d%% full"), ((fifo_size-bytes) * 100) / fifo_size); mvwaddnstr(proc_out_win, 0, 1, buf, (fifo_for_maxx)-2); bytes = read(fd, &buf, 16384); if(bytes < 1) return 0; if(bytes <= (fifo_size - proc_fifo_in)) { memcpy((proc_fifo + proc_fifo_in), buf, bytes); proc_fifo_in += bytes; if(proc_fifo_in == fifo_size) proc_fifo_in = 0; return 1; } memcpy((proc_fifo + proc_fifo_in), &buf, (fifo_size - proc_fifo_in)); bytes -= (fifo_size - proc_fifo_in); memcpy(proc_fifo, &(buf[fifo_size - proc_fifo_in]), bytes); proc_fifo_in = bytes; return 1; } int get_fifo(int fd) { char buf[16384]; int bytes, fifo_size, remain; fifo_size = of_fifo_buf * 1024; if(proc_fifo_in == proc_fifo_out) return 0; bytes = proc_fifo_in - proc_fifo_out; if(bytes < 0) bytes = (fifo_size - proc_fifo_out) + proc_fifo_in; sprintf(buf, "FIFO: %3d%% full", (bytes * 100) / fifo_size); mvwaddnstr(proc_out_win, 0, 1, buf, (fifo_for_maxx)-2); if(proc_fifo_out > proc_fifo_in) { bytes = fifo_size - proc_fifo_out; if(bytes < 16384) { memcpy(&buf, (proc_fifo + proc_fifo_out), bytes); } else { memcpy(&buf, (proc_fifo + proc_fifo_out), 16384); bytes = 16384; } if(bytes < 16384) { remain = proc_fifo_in; if(remain + bytes > 16384) { memcpy(&(buf[bytes]), proc_fifo, 16384-bytes); bytes = 16384; } else { memcpy(&(buf[bytes]), proc_fifo, remain); bytes += remain; } } } else { remain = proc_fifo_in - proc_fifo_out; if(remain > 16384) { memcpy(&buf, (proc_fifo + proc_fifo_out), 16384); bytes = 16384; } else { memcpy(&buf, (proc_fifo + proc_fifo_out), remain); bytes = remain; } } bytes = write(fd, &buf, bytes); if(bytes > 0) { proc_fifo_out = (proc_fifo_out + bytes) % fifo_size; return 1; } return 0; } int conv_on_fly(song_typ *track) { int new_pipe1[2]; int new_pipe2[2]; int new_pipe3[2]; char *cmd_line; char **cmd_args; int status; int eval_cou; char *filenm; filenm = build_mp3_filenm(track); if(create_sub_dirs(filenm, TRUE)) return 1; if(access(filenm, F_OK) == 0) { /* mp3 file already exists */ if(access(filenm, W_OK) != 0) { /* but could not overwritten */ popup_error_win(_("mp3-file already exists and isn't writable")); return 1; } /* ask if it is allowed to overwrite */ cmd_line = (char *) malloc(sizeof(char) * (strlen(filenm)+50)); if(cmd_line == NULL) { perror("malloc"); wuuush(1); } sprintf(cmd_line, _("overwrite \"%s\"?"), filenm); if(! select_yesno_box(cmd_line)) { free(cmd_line); return 2; } free(cmd_line); } if(! str_path_check(def_cd_rip_of)) { popup_error_win(_("no ripper for on-fly in $PATH")); return 1; } if(! str_path_check(def_mp3_enc_of)) { popup_error_win(_("no encoder for on-fly in $PATH")); return 1; } if(pipe(new_pipe1) != 0) { popup_error_win(_("error opening pipe for STDOUT")); return 1; } if(pipe(new_pipe2) != 0) { popup_error_win(_("error opening pipe for STDERR")); return 1; } proc_stdout1 = new_pipe1[0]; /* wav-data from ripper */ proc_stderr1 = new_pipe2[0]; /* status from ripper */ proc_child1 = fork(); /* ripper subprocesss */ if(proc_child1 == -1) { popup_error_win(_("could not fork")); return 1; } if(proc_child1 == 0) { if(dup2(new_pipe1[1], STDOUT_FILENO) == -1) { exit(EXIT_FAILURE); } if(dup2(new_pipe2[1], STDERR_FILENO) == -1) { exit(EXIT_FAILURE); } close(new_pipe1[0]); close(new_pipe2[0]); close(proc_stdout1); close(proc_stderr1); cmd_line = create_sub_string(track, 4); /* on-fly ripping */ if(! cmd_line) { exit(EXIT_FAILURE); } cmd_args = build_arg_tree(cmd_line); if(! cmd_args) { exit(EXIT_FAILURE); } execvp(cmd_args[0], cmd_args); exit(EXIT_FAILURE); } proc_fifo = (char *) malloc(sizeof(char) * 1024 * of_fifo_buf); if(! proc_fifo) { perror("malloc"); wuuush(1); } proc_fifo_in = 0; proc_fifo_out = 0; proc_sub = (char *) malloc(sizeof(char) * 50); if(! proc_sub) { perror("malloc"); wuuush(1); } sprintf(proc_sub, _("converting track %d..."), (track->toc)+1); open_process_win(proc_sub); /* child started */ fcntl(proc_stdout1, F_SETFL, O_NONBLOCK); close(new_pipe1[1]); fcntl(proc_stderr1, F_SETFL, O_NONBLOCK); close(new_pipe2[1]); while(1) { if(waitpid(proc_child1, &status, WNOHANG) == proc_child1) break; if(evaluate_proc(proc_stderr1, -1, -1, TRUE, FALSE)) { status = 65530; break; } while(put_fifo(proc_stdout1)); if(proc_fifo_in > ((of_fifo_buf*1024)>>1)) { status = 65531; break; } usleep(250); } if((status != 65531) && (status != 65530) && (WEXITSTATUS(status) != EXIT_SUCCESS)) { /* give the user the chance to read any failure notice */ shell_wait_for_close_proc(proc_stderr1, -1, -1); } if((status != 65531) && (WEXITSTATUS(status) == EXIT_SUCCESS)) { status = 65531; proc_child1 = 0; } if(status != 65531) { /* Terminate */ free(proc_fifo); free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); if(status == 65530) { kill(proc_child1, SIGINT); popup_error_win(_("action was canceled")); kill(proc_child1, SIGKILL); return 1; } popup_error_win(_("child (cd-ripper) died unexpected")); return 1; } /* FIFO (half)-full, or ripping ended; start now encoder */ if(pipe(new_pipe1) != 0) { kill(proc_child1, SIGINT); popup_error_win(_("error opening pipe for STDOUT")); free(proc_fifo); free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); kill(proc_child1, SIGKILL); return 1; } if(pipe(new_pipe2) != 0) { kill(proc_child1, SIGINT); popup_error_win(_("error opening pipe for STDERR")); free(proc_fifo); free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); kill(proc_child1, SIGKILL); return 1; } if(pipe(new_pipe3) != 0) { kill(proc_child1, SIGINT); popup_error_win(_("error opening pipe for STDIN")); free(proc_fifo); free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); kill(proc_child1, SIGKILL); return 1; } proc_stdout2 = new_pipe1[0]; proc_stderr2 = new_pipe2[0]; proc_stdin2 = new_pipe3[1]; proc_child2 = fork(); /* encoder process */ if(proc_child2 == -1) { kill(proc_child1, SIGINT); popup_error_win(_("forking for encoder subprocess failed")); free(proc_fifo); free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); kill(proc_child1, SIGKILL); return 1; } if(proc_child2 == 0) { if(dup2(new_pipe1[1], STDOUT_FILENO) == -1) { exit(EXIT_FAILURE); } if(dup2(new_pipe2[1], STDERR_FILENO) == -1) { exit(EXIT_FAILURE); } if(dup2(new_pipe3[0], STDIN_FILENO) == -1) { exit(EXIT_FAILURE); } close(new_pipe1[0]); close(new_pipe2[0]); close(new_pipe3[1]); cmd_line = create_sub_string(track, 2); /* on-fly encoding */ if(! cmd_line) { exit(EXIT_FAILURE); } cmd_args = build_arg_tree(cmd_line); if(! cmd_args) { exit(EXIT_FAILURE); } execvp(cmd_args[0], cmd_args); exit(EXIT_FAILURE); } fcntl(proc_stdout2, F_SETFL, O_NONBLOCK); close(new_pipe1[1]); fcntl(proc_stderr2, F_SETFL, O_NONBLOCK); close(new_pipe2[1]); fcntl(proc_stdin2, F_SETFL, O_NONBLOCK); close(new_pipe3[0]); while(1) { if(proc_child1) { if(waitpid(proc_child1, &status, WNOHANG) == proc_child1) { if(WEXITSTATUS(status) != EXIT_SUCCESS) { kill(proc_child2, SIGINT); popup_error_win(_("child (cd-ripper) died unexpected")); free(proc_fifo); free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); close(proc_stdout2); close(proc_stderr2); close(proc_stdin2); kill(proc_child2, SIGKILL); return 1; } proc_child1 = 0; } } if(waitpid(proc_child2, &status, WNOHANG) == proc_child2) break; for(eval_cou=0;eval_cou<10;eval_cou++) { if(proc_child1) put_fifo(proc_stdout1); get_fifo(proc_stdin2); usleep(250); } if(proc_child1 && evaluate_proc(proc_stderr1, proc_stdout2, proc_stderr2, TRUE, FALSE)) { status = 65530; break; } else if(evaluate_proc(proc_stdout2, proc_stderr2, -1, TRUE, FALSE)) { status = 65530; break; } /* close pipes if ripping is ready and fifo empty */ if((! proc_child1) && (proc_fifo_in == proc_fifo_out)) { close(proc_stdin2); } } /* Terminate */ if(status != 65530 && WEXITSTATUS(status) != EXIT_SUCCESS) { /* give the user the chance to read any failure notice */ shell_wait_for_close_proc(proc_stderr1, proc_stdout2, proc_stderr2); } free(proc_sub); free(proc_fifo); del_process_win(); close(proc_stdout1); close(proc_stderr1); close(proc_stdout2); close(proc_stderr2); close(proc_stdin2); if(status == 65530) { kill(proc_child1, SIGINT); kill(proc_child2, SIGINT); popup_error_win(_("action was canceled")); kill(proc_child1, SIGKILL); kill(proc_child2, SIGKILL); return 1; } if(WEXITSTATUS(status) == EXIT_SUCCESS) return 0; popup_error_win(_("child (encoder) died unexpected")); return 1; } int set_mp3_inf(song_typ *track) { int new_pipe1[2]; int new_pipe2[2]; char *cmd_line; char **cmd_args; int status; if(def_mp3_info && strcmp(def_mp3_info, "0") == 0) { return 0; } if(! str_path_check(def_mp3_info)) { popup_error_win(_("missing mp3-info program")); return 1; } if(pipe(new_pipe1) != 0) { popup_error_win(_("error opening pipe for STDOUT")); return 1; } if(pipe(new_pipe2) != 0) { popup_error_win(_("error opening pipe for STDERR")); return 1; } proc_stdout1 = new_pipe1[0]; proc_stderr1 = new_pipe2[0]; proc_child1 = fork(); if(proc_child1 == -1) { popup_error_win(_("forking not possible")); return 1; } if(proc_child1 == 0) { if(dup2(new_pipe1[1], STDOUT_FILENO) == -1) { exit(EXIT_FAILURE); } if(dup2(new_pipe2[1], STDERR_FILENO) == -1) { exit(EXIT_FAILURE); } close(new_pipe1[0]); close(new_pipe2[0]); close(proc_stdout1); close(proc_stderr1); cmd_line = create_sub_string(track, 5); /* set mp3 info */ if(! cmd_line) { exit(EXIT_FAILURE); } cmd_args = build_arg_tree(cmd_line); if(! cmd_args) { exit(EXIT_FAILURE); } execvp(cmd_args[0], cmd_args); exit(EXIT_FAILURE); } /* child started */ fcntl(proc_stdout1, F_SETFL, O_NONBLOCK); close(new_pipe1[1]); fcntl(proc_stderr1, F_SETFL, O_NONBLOCK); close(new_pipe2[1]); proc_sub = (char *) malloc(sizeof(char) * 100); if(! proc_sub) { perror("malloc"); wuuush(1); } sprintf(proc_sub, _("setting mp3-infos for track %d..."), (track->toc)+1); open_process_win(proc_sub); while(1) { if(waitpid(proc_child1, &status, WNOHANG) == proc_child1) break; if(evaluate_proc(proc_stdout1, proc_stderr1, -1, FALSE, FALSE)) { status = 65530; break; } } /* Terminate */ if(status != 65530 && WEXITSTATUS(status) != EXIT_SUCCESS) { /* give the user the chance to read any failure notice */ shell_wait_for_close_proc(proc_stdout1, proc_stderr1, -1); } free(proc_sub); del_process_win(); close(proc_stdout1); close(proc_stderr1); if(status == 65530) { kill(proc_child1, SIGINT); popup_error_win(_("action was canceled")); kill(proc_child1, SIGKILL); return 1; } if(WEXITSTATUS(status) == EXIT_SUCCESS) return 0; popup_error_win(_("child (mp3-info) died unexpected")); return 1; } /* Check if a program is in $PATH */ BOOL prg_path_check(char *program) { char *path; int i,j; char *name; /* first check if program is given with absolut path */ if(*program == '/') { if(! access(program, X_OK)) return TRUE; else return FALSE; } /* maybe it is given with a relative path, so check this now */ if(! access(program, X_OK)) return TRUE; path = getenv("PATH"); if(! path) return TRUE; /* no path defined, could not determine, so return TRUE */ j = 0; i = 0; while(1) { if((*(path+j) == 0) || (*(path+j) == ';') || (*(path+j) == ':')) { if(j != i) { name = (char *) malloc(sizeof(char) * (strlen(program) + (j-i) + 2)); if(! name) { wuuush(1); } memcpy(name, (path+i), j-i); *(name + (j-i)) = '/'; memcpy(name + (j-i) + 1, program, strlen(program)); *(name + (j-i) + strlen(program) + 1) = 0; if(! access(name, X_OK)) { free(name); return TRUE; } free(name); } /* IF j != i */ if(*(path+j) == 0) return FALSE; j++; i=j; } else { j++; } /* IF */ } /* WHILE */ } /* Check if program in string is in $PATH */ BOOL str_path_check(char *program) { char *prg; int i,j; BOOL quote; BOOL start; if(! program) return FALSE; i=0; j=0; quote = FALSE; start = FALSE; while(*(program+j)) { if(*(program+j) == ' ') { if(! start) i = j+1; else { if(! quote) { j--; break; } } } else if(*(program+j) == '\"') { if(! start) { i = j+1; quote = TRUE; } else { if(quote) { j--; break; } } } else { start = TRUE; } j++; } if(j-i < 0) return FALSE; prg = (char *) malloc(sizeof(char) * ((j-i) + 2)); if(! prg) { wuuush(1); } memcpy(prg, (program+i), (j-i)+1); *(prg + (j-i) + 1) = 0; start = prg_path_check(prg); free(prg); return start; }