1 /*MT*
2 
3     MediaTomb - http://www.mediatomb.cc/
4 
5     process.cc - this file is part of MediaTomb.
6 
7     Copyright (C) 2005 Gena Batyan <bgeradz@mediatomb.cc>,
8                        Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>
9 
10     Copyright (C) 2006-2010 Gena Batyan <bgeradz@mediatomb.cc>,
11                             Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>,
12                             Leonhard Wimmer <leo@mediatomb.cc>
13 
14     MediaTomb is free software; you can redistribute it and/or modify
15     it under the terms of the GNU General Public License version 2
16     as published by the Free Software Foundation.
17 
18     MediaTomb is distributed in the hope that it will be useful,
19     but WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21     GNU General Public License for more details.
22 
23     You should have received a copy of the GNU General Public License
24     version 2 along with MediaTomb; if not, write to the Free Software
25     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
26 
27     $Id$
28 */
29 
30 /// \file process.cc
31 
32 #include "process.h" // API
33 
34 #include <cerrno>
35 #include <csignal>
36 #include <cstdio>
37 #include <cstring>
38 #include <sstream>
39 #include <thread>
40 
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <sys/wait.h>
44 #include <unistd.h>
45 
46 #include "config/config_manager.h"
47 #include "util/tools.h"
48 
49 #define BUF_SIZE 256
50 
run_simple_process(const std::shared_ptr<Config> & cfg,const std::string & prog,const std::string & param,const std::string & input)51 std::string run_simple_process(const std::shared_ptr<Config>& cfg, const std::string& prog, const std::string& param, const std::string& input)
52 {
53     std::FILE* file;
54     int fd;
55 
56     /* creating input file */
57     char temp_in[] = "mt_in_XXXXXX";
58     char temp_out[] = "mt_out_XXXXXX";
59 
60     std::string input_file = tempName(cfg->getOption(CFG_SERVER_TMPDIR), temp_in);
61 #ifdef __linux__
62     fd = open(input_file.c_str(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, S_IRUSR | S_IWUSR);
63 #else
64     fd = open(input_file.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
65 #endif
66     if (fd == -1) {
67         log_debug("Failed to open input file {}: {}", input_file, std::strerror(errno));
68         throw_std_runtime_error("Failed to open input file {}: {}", input_file, std::strerror(errno));
69     }
70     std::size_t ret = write(fd, input.c_str(), input.length());
71     close(fd);
72     if (ret < input.length()) {
73         log_debug("Failed to write to {}: {}", input, std::strerror(errno));
74         throw_std_runtime_error("Failed to write to {}: {}", input, std::strerror(errno));
75     }
76 
77     /* touching output file */
78     std::string output_file = tempName(cfg->getOption(CFG_SERVER_TMPDIR), temp_out);
79 #ifdef __linux__
80     fd = open(output_file.c_str(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, S_IRUSR | S_IWUSR);
81 #else
82     fd = open(output_file.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
83 #endif
84     if (fd == -1) {
85         log_debug("Failed to open output file {}: {}", output_file, std::strerror(errno));
86         throw_std_runtime_error("Failed to open output file {}: {}", output_file, std::strerror(errno));
87     }
88     close(fd);
89 
90     /* executing script */
91     auto command = fmt::format("{} {} < {} > {}", prog, param, input_file, output_file);
92     log_debug("running {}", command);
93     int sysret = std::system(command.c_str());
94     if (sysret == -1) {
95         log_debug("Failed to execute: {}", command);
96         throw_std_runtime_error("Failed to execute: {}", command);
97     }
98 
99     /* reading output file */
100 #ifdef __linux__
101     file = std::fopen(output_file.c_str(), "re");
102 #else
103     file = std::fopen(output_file.c_str(), "r");
104 #endif
105     if (!file) {
106         log_debug("Could not open output file {}: {}", output_file, std::strerror(errno));
107         throw_std_runtime_error("Failed to open output file {}: {}", output_file, std::strerror(errno));
108     }
109 
110     std::ostringstream output;
111     int bytesRead;
112     char buf[BUF_SIZE];
113     while (true) {
114         bytesRead = std::fread(buf, 1, BUF_SIZE, file);
115         if (bytesRead > 0)
116             output << std::string(buf, bytesRead);
117         else
118             break;
119     }
120     std::fclose(file);
121 
122     /* removing input and output files */
123     unlink(input_file.c_str());
124     unlink(output_file.c_str());
125 
126     return output.str();
127 }
128 
is_alive(pid_t pid,int * status)129 bool is_alive(pid_t pid, int* status)
130 {
131     return waitpid(pid, status, WNOHANG) == 0;
132 }
133 
kill_proc(pid_t kill_pid)134 bool kill_proc(pid_t kill_pid)
135 {
136     if (!is_alive(kill_pid))
137         return true;
138 
139     log_debug("KILLING TERM PID: {}", kill_pid);
140     kill(kill_pid, SIGTERM);
141     std::this_thread::sleep_for(std::chrono::seconds(1));
142 
143     if (!is_alive(kill_pid))
144         return true;
145 
146     log_debug("KILLING INT PID: {}", kill_pid);
147     kill(kill_pid, SIGINT);
148     std::this_thread::sleep_for(std::chrono::seconds(1));
149 
150     if (!is_alive(kill_pid))
151         return true;
152 
153     log_debug("KILLING KILL PID: {}", kill_pid);
154     kill(kill_pid, SIGKILL);
155     std::this_thread::sleep_for(std::chrono::seconds(1));
156 
157     return !is_alive(kill_pid);
158 }
159