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