Handle hostnames with upper-case letters
[webmin.git] / proc / proc-lib.pl.bak
1 # proc-lib.pl
2 # Functions for managing processes
3
4 do '../web-lib.pl';
5 &init_config();
6 do "$config{ps_style}-lib.pl";
7 use POSIX;
8 %access = &get_module_acl();
9 map { $hide{$_}++ } split(/\s+/, $access{'hide'});
10
11 sub process_info
12 {
13 local @plist = &list_processes($_[0]);
14 return @plist ? %{$plist[0]} : ();
15 }
16
17 # index_links(current)
18 sub index_links
19 {
20 local(%linkname, $l);
21 print "<b>$text{'index_display'} : </b>&nbsp;&nbsp;\n";
22 foreach $l ("tree", "user", "size", "cpu", "search", "run") {
23         next if ($l eq "run" && !$access{'run'});
24         if ($l ne $_[0]) { print "<a href=index_$l.cgi>"; }
25         else { print "<b>"; }
26         print $text{"index_$l"};
27         if ($l ne $_[0]) { print "</a>"; }
28         else { print "</b>"; }
29         print "&nbsp;\n";
30         }
31 print "<p>\n";
32 open(INDEX, "> $module_config_directory/index");
33 $0 =~ /([^\/]+)$/;
34 print INDEX "$1?$in\n";
35 close(INDEX);
36 }
37
38 sub cut_string
39 {
40 if (length($_[0]) > $_[1]) {
41         return substr($_[0], 0, $_[1])." ...";
42         }
43 return $_[0];
44 }
45
46 # switch_acl_uid()
47 sub switch_acl_uid
48 {
49 if ($access{'uid'} < 0) {
50         local @u = getpwnam($remote_user);
51         $( = $u[3]; $) = "$u[3] $u[3]";
52         ($>, $<) = ($u[2], $u[2]);
53         }
54 elsif ($access{'uid'}) {
55         local @u = getpwuid($access{'uid'});
56         $( = $u[3]; $) = "$u[3] $u[3]";
57         ($>, $<) = ($u[2], $u[2]);
58         }
59 }
60
61 # safe_process_exec(command, uid, gid, handle, input, fixtags, bsmode)
62 # Executes the given command as the given user/group and writes all output
63 # to the given file handle. Finishes when there is no more output or the
64 # process stops running. Returns the number of bytes read.
65 sub safe_process_exec
66 {
67 # setup pipes and fork the process
68 local $chld = $SIG{'CHLD'};
69 $SIG{'CHLD'} = \&safe_exec_reaper;
70 pipe(OUTr, OUTw);
71 pipe(INr, INw);
72 local $pid = fork();
73 if (!$pid) {
74         #setsid();
75         untie(*STDIN);
76         untie(*STDOUT);
77         untie(*STDERR);
78         open(STDIN, "<&INr");
79         open(STDOUT, ">&OUTw");
80         open(STDERR, ">&OUTw");
81         $| = 1;
82         close(OUTr); close(INw);
83
84         if ($_[1]) {
85                 if (defined($_[2])) {
86                         # switch to given UID and GID
87                         $( = $_[2]; $) = "$_[2] $_[2]";
88                         ($>, $<) = ($_[1], $_[1]);
89                         }
90                 else {
91                         # switch to UID and all GIDs
92                         local @u = getpwuid($_[1]);
93                         $( = $u[3];
94                         $) = "$u[3] ".join(" ", $u[3], &other_groups($u[0]));
95                         ($>, $<) = ($u[2], $u[2]);
96                         }
97                 }
98
99         # run the command
100         delete($ENV{'FOREIGN_MODULE_NAME'});
101         delete($ENV{'SCRIPT_NAME'});
102         exec("/bin/sh", "-c", $_[0]);
103         print "Exec failed : $!\n";
104         exit 1;
105         }
106 close(OUTw); close(INr);
107
108 # Feed input (if any)
109 print INw $_[4];
110 close(INw);
111
112 # Read and show output
113 local $fn = fileno(OUTr);
114 local $got = 0;
115 local $out = $_[3];
116 local $line;
117 while(1) {
118         local ($rmask, $buf);
119         vec($rmask, $fn, 1) = 1;
120         local $sel = select($rmask, undef, undef, 1);
121         if ($sel > 0 && vec($rmask, $fn, 1)) {
122                 # got something to read.. print it
123                 sysread(OUTr, $buf, 1024) || last;
124                 $got += length($buf);
125                 if ($_[5]) {
126                         $buf = &html_escape($buf);
127                         }
128                 if ($_[6]) {
129                         # Convert backspaces and returns
130                         $line .= $buf;
131                         while($line =~ s/^([^\n]*\n)//) {
132                                 local $one = $1;
133                                 while($one =~ s/.\010//) { }
134                                 print $out $one;
135                                 }
136                         }
137                 else {
138                         print $out $buf;
139                         }
140                 }
141         elsif ($sel == 0) {
142                 # nothing to read. maybe the process is done, and a subprocess
143                 # is hanging things up
144                 last if (!kill(0, $pid));
145                 }
146         }
147 close(OUTr);
148 print $out $line;
149 $SIG{'CHLD'} = $chld;
150 return $got;
151 }
152
153 # safe_process_exec_logged(..)
154 # Like safe_process_exec, but also logs the command
155 sub safe_process_exec_logged
156 {
157 &additional_log('exec', undef, $_[0]);
158 return &safe_process_exec(@_);
159 }
160
161 sub safe_exec_reaper
162 {
163 local $xp;
164 do {    local $oldexit = $?;
165         $xp = waitpid(-1, WNOHANG);
166         $? = $oldexit if ($? < 0);
167         } while($xp > 0);
168 }
169
170 # pty_process_exec(command, [uid, gid])
171 # Starts the given command in a new pty and returns the pty filehandle and PID
172 sub pty_process_exec
173 {
174 local ($ptyfh, $ttyfh, $pty, $tty) = &get_new_pty();
175 local $pid = fork();
176 if (!$pid) {
177         close(STDIN); close(STDOUT); close(STDERR);
178         untie(*STDIN); untie(*STDOUT); untie(*STDERR);
179         setsid();
180         #setpgrp(0, $$);
181         if ($_[1]) {
182                 $( = $u[3]; $) = "$_[2] $_[2]";
183                 ($>, $<) = ($_[1], $_[1]);
184                 }
185         open(STDIN, "<$tty");
186         open(STDOUT, ">&$ttyfh");
187         open(STDERR, ">&STDOUT");
188         close($ptyfh);
189         exec($_[0]);
190         print "Exec failed : $!\n";
191         exit 1;
192         }
193 close($ttyfh);
194 return ($ptyfh, $pid);
195 }
196
197 # pty_process_exec_logged(..)
198 # Like pty_process_exec, but logs the command as well
199 sub pty_process_exec_logged
200 {
201 &additional_log('exec', undef, $_[0]);
202 return &pty_process_exec(@_);
203 }
204
205 # find_process(name)
206 # Returns an array of all processes matching some name
207 sub find_process
208 {
209 local $name = $_[0];
210 local @rv = grep { $_->{'args'} =~ /$name/ } &list_processes();
211 return wantarray ? @rv : $rv[0];
212 }
213
214 $has_lsof_command = &has_command("lsof");
215
216 # find_socket_processes(protocol, port)
217 # Returns all processes using some port and protocol
218 sub find_socket_processes
219 {
220 local @rv;
221 open(LSOF, "lsof -i '$_[0]:$_[1]' |");
222 while(<LSOF>) {
223         if (/^(\S+)\s+(\d+)/) {
224                 push(@rv, $2);
225                 }
226         }
227 close(LSOF);
228 return @rv;
229 }
230
231 # find_process_sockets(pid)
232 # Returns all network connections made by some process
233 sub find_process_sockets
234 {
235 local @rv;
236 open(LSOF, "lsof -i tcp -i udp -n |");
237 while(<LSOF>) {
238         if (/^(\S+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+).*(TCP|UDP)\s+(.*)/
239             && $2 eq $_[0]) {
240                 local $n = { 'fd' => $4,
241                              'type' => $5,
242                              'proto' => $7 };
243                 local $m = $8;
244                 if ($m =~ /^([^:\s]+):([^:\s]+)\s+\(listen\)/i) {
245                         $n->{'lhost'} = $1;
246                         $n->{'lport'} = $2;
247                         $n->{'listen'} = 1;
248                         }
249                 elsif ($m =~ /^([^:\s]+):([^:\s]+)->([^:\s]+):([^:\s]+)\s+\((\S+)\)/) {
250                         $n->{'lhost'} = $1;
251                         $n->{'lport'} = $2;
252                         $n->{'rhost'} = $3;
253                         $n->{'rport'} = $4;
254                         $n->{'state'} = $5;
255                         }
256                 elsif ($m =~ /^([^:\s]+):([^:\s]+)/) {
257                         $n->{'lhost'} = $1;
258                         $n->{'lport'} = $2;
259                         }
260                 push(@rv, $n);
261                 }
262         }
263 close(LSOF);
264 return @rv;
265 }
266
267 # find_process_files(pid)
268 # Returns all files currently held open by some process
269 sub find_process_files
270 {
271 local @rv;
272 open(LSOF, "lsof -p '$_[0]' |");
273 while(<LSOF>) {
274         if (/^(\S+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\d+),(\d+)\s+(\d+)\s+(\d+)\s+(.*)/) {
275                 push(@rv, { 'fd' => lc($4),
276                             'type' => lc($5),
277                             'device' => [ $6, $7 ],
278                             'size' => $8,
279                             'inode' => $9,
280                             'file' => $10 });
281                 }
282         }
283 close(LSOF);
284 return @rv;
285 }
286
287
288 1;
289