1 : // Copyright (C) Andrew Tridgell 2002 (original file)
2 : // Copyright (C) 2006 Red Hat Inc. (systemtap changes)
3 : //
4 : // This program is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU General Public License as
6 : // published by the Free Software Foundation; either version 2 of the
7 : // License, or (at your option) any later version.
8 : //
9 : // This program is distributed in the hope that it will be useful, but
10 : // WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
12 : // General Public License for more details.
13 : //
14 : // You should have received a copy of the GNU General Public License
15 : // along with this program; if not, write to the Free Software
16 : // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 :
18 : #include "util.h"
19 : #include <stdexcept>
20 : #include <cerrno>
21 :
22 : extern "C" {
23 : #include <sys/types.h>
24 : #include <sys/stat.h>
25 : #include <pwd.h>
26 : #include <unistd.h>
27 : #include <stdlib.h>
28 : #include <fcntl.h>
29 : }
30 :
31 : using namespace std;
32 :
33 :
34 : // Return current users home directory or die.
35 : const char *
36 0 : get_home_directory(void)
37 : {
38 0 : const char *p = getenv("HOME");
39 0 : if (p)
40 0 : return p;
41 :
42 0 : struct passwd *pwd = getpwuid(getuid());
43 0 : if (pwd)
44 0 : return pwd->pw_dir;
45 :
46 0 : throw runtime_error("Unable to determine home directory");
47 : return NULL;
48 : }
49 :
50 :
51 : // Copy a file. The copy is done via a temporary file and atomic
52 : // rename.
53 : int
54 669 : copy_file(const char *src, const char *dest)
55 : {
56 : int fd1, fd2;
57 : char buf[10240];
58 : int n;
59 669 : string tmp;
60 : char *tmp_name;
61 : mode_t mask;
62 :
63 : // Open the src file.
64 669 : fd1 = open(src, O_RDONLY);
65 669 : if (fd1 == -1)
66 0 : return -1;
67 :
68 : // Open the temporary output file.
69 669 : tmp = dest + string(".XXXXXX");
70 1338 : tmp_name = (char *)tmp.c_str();
71 669 : fd2 = mkstemp(tmp_name);
72 669 : if (fd2 == -1)
73 : {
74 0 : close(fd1);
75 0 : return -1;
76 : }
77 :
78 : // Copy the src file to the temporary output file.
79 44876 : while ((n = read(fd1, buf, sizeof(buf))) > 0)
80 : {
81 43538 : if (write(fd2, buf, n) != n)
82 : {
83 0 : close(fd2);
84 0 : close(fd1);
85 0 : unlink(tmp_name);
86 0 : return -1;
87 : }
88 : }
89 669 : close(fd1);
90 :
91 : // Set the permissions on the temporary output file.
92 669 : mask = umask(0);
93 669 : fchmod(fd2, 0666 & ~mask);
94 669 : umask(mask);
95 :
96 : // Close the temporary output file. The close can fail on NFS if
97 : // out of space.
98 669 : if (close(fd2) == -1)
99 : {
100 0 : unlink(tmp_name);
101 0 : return -1;
102 : }
103 :
104 : // Rename the temporary output file to the destination file.
105 669 : unlink(dest);
106 669 : if (rename(tmp_name, dest) == -1)
107 : {
108 0 : unlink(tmp_name);
109 0 : return -1;
110 : }
111 :
112 669 : return 0;
113 : }
114 :
115 :
116 : // Make sure a directory exists.
117 : int
118 2533 : create_dir(const char *dir)
119 : {
120 : struct stat st;
121 2533 : if (stat(dir, &st) == 0)
122 : {
123 2350 : if (S_ISDIR(st.st_mode))
124 2348 : return 0;
125 2 : errno = ENOTDIR;
126 2 : return 1;
127 : }
128 :
129 183 : if (mkdir(dir, 0777) != 0 && errno != EEXIST)
130 0 : return 1;
131 :
132 183 : return 0;
133 : }
134 :
135 :
136 : void
137 : tokenize(const string& str, vector<string>& tokens,
138 347 : const string& delimiters = " ")
139 : {
140 : // Skip delimiters at beginning.
141 347 : string::size_type lastPos = str.find_first_not_of(delimiters, 0);
142 : // Find first "non-delimiter".
143 347 : string::size_type pos = str.find_first_of(delimiters, lastPos);
144 :
145 2082 : while (pos != string::npos || lastPos != string::npos)
146 : {
147 : // Found a token, add it to the vector.
148 1388 : tokens.push_back(str.substr(lastPos, pos - lastPos));
149 : // Skip delimiters. Note the "not_of"
150 1388 : lastPos = str.find_first_not_of(delimiters, pos);
151 : // Find next "non-delimiter"
152 1388 : pos = str.find_first_of(delimiters, lastPos);
153 : }
154 347 : }
155 :
156 :
157 : // Find an executable by name in $PATH.
158 : bool
159 347 : find_executable(const char *name, string& retpath)
160 : {
161 : const char *p;
162 347 : string path;
163 347 : vector<string> dirs;
164 : struct stat st1, st2;
165 :
166 347 : if (*name == '/')
167 : {
168 0 : retpath = name;
169 0 : return true;
170 : }
171 :
172 347 : p = getenv("PATH");
173 347 : if (!p)
174 0 : return false;
175 347 : path = p;
176 :
177 : // Split PATH up.
178 347 : tokenize(path, dirs, string(":"));
179 :
180 : // Search the path looking for the first executable of the right name.
181 694 : for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++)
182 : {
183 1041 : string fname = *i + "/" + name;
184 1041 : const char *f = fname.c_str();
185 :
186 : // Look for a normal executable file.
187 1041 : if (access(f, X_OK) == 0
188 : && lstat(f, &st1) == 0
189 : && stat(f, &st2) == 0
190 : && S_ISREG(st2.st_mode))
191 : {
192 : // Found it!
193 347 : retpath = fname;
194 347 : return true;
195 : }
196 : }
197 :
198 0 : return false;
199 : }
200 :
201 68 : const string cmdstr_quoted(const string& cmd)
202 : {
203 : // original cmd : substr1
204 : // or : substr1'substr2
205 : // or : substr1'substr2'substr3......
206 : // after quoted :
207 : // every substr(even it's empty) is quoted by ''
208 : // every single-quote(') is quoted by ""
209 : // examples: substr1 --> 'substr1'
210 : // substr1'substr2 --> 'substr1'"'"'substr2'
211 :
212 68 : string quoted_cmd;
213 68 : string quote("'");
214 136 : string replace("'\"'\"'");
215 68 : string::size_type pos = 0;
216 :
217 68 : quoted_cmd += quote;
218 68 : for (string::size_type quote_pos = cmd.find(quote, pos);
219 : quote_pos != string::npos;
220 : quote_pos = cmd.find(quote, pos)) {
221 0 : quoted_cmd += cmd.substr(pos, quote_pos - pos);
222 0 : quoted_cmd += replace;
223 0 : pos = quote_pos + 1;
224 : }
225 68 : quoted_cmd += cmd.substr(pos, cmd.length() - pos);
226 68 : quoted_cmd += quote;
227 :
228 68 : return quoted_cmd;
229 2188 : }
230 1094 :
|