Skip to content
Newer
Older
100644 460 lines (385 sloc) 13.6 KB
38fb85e @klacke ""
authored
1 %%%----------------------------------------------------------------------
2 %%% File : yaws_ctl.erl
3 %%% Author : Claes Wikstrom <klacke@bluetail.com>
4 %%% Purpose :
5 %%% Created : 29 Apr 2002 by Claes Wikstrom <klacke@bluetail.com>
6 %%%----------------------------------------------------------------------
7
8
9 %% some code to remoteley control a running yaws server
10
11 -module(yaws_ctl).
12 -author('klacke@bluetail.com').
13
14 -include_lib("kernel/include/file.hrl").
6cf3ece @klacke ""
authored
15 -include("../include/yaws.hrl").
16 -include("../include/yaws_api.hrl").
28e4c73 @klacke first attempt to run properly under cygwin
authored
17 -include("yaws_debug.hrl").
2f51c68 @klacke -check arg
authored
18
9a74e5a @klacke Major general code cleanup, finally got rid of all the export_all sta…
authored
19 -export([start/2, actl_trace/1]).
20 -export([ls/1,hup/1,stop/1,status/1,load/1,
5207102 @klacke Added debug dump functionality
authored
21 check/1,trace/1, debug_dump/1]).
9a74e5a @klacke Major general code cleanup, finally got rid of all the export_all sta…
authored
22 %% internal
23 -export([run/1, aloop/3]).
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
24
25
26 %% assumes the appropriate file structures
27 %% are already created with the right perms
28
6dc4cca @klacke ""
authored
29 start(_GC, FirstTime) when FirstTime == false ->
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
30 ok;
31 start(GC, true) ->
d07115c @klacke Several cleanups due to dialyzer, also moved the control file into us…
authored
32 proc_lib:start_link(?MODULE, run, [GC]).
28e4c73 @klacke first attempt to run properly under cygwin
authored
33
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
34
35 run(GC) ->
36 %% First check if there is already a Yaws system running
37 %% with the same sid.
38 case connect(GC#gconf.id) of
0be3c7e @klacke untabified all of yaws
authored
39 {ok, Sock, _Key} ->
40 %% Not good, let's get some sys info
41 %% from that system so we can produce a good error
42 %% message
43 gen_tcp:close(Sock),
44 e("There is already a yaws system running with the same ~n"
d07115c @klacke Several cleanups due to dialyzer, also moved the control file into us…
authored
45 " id <~p> on this computer and this user, ~n"
0be3c7e @klacke untabified all of yaws
authored
46 " set another id in the yaws conf file ~n",
47 [GC#gconf.id]);
48 {error, eaccess} ->
49 %% We're not allowed to open the ctl file
d07115c @klacke Several cleanups due to dialyzer, also moved the control file into us…
authored
50 e("Error reading ~s, you don't have access rights to read it",
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
51 [yaws:ctl_file(GC#gconf.id)]);
0be3c7e @klacke untabified all of yaws
authored
52 {error, _} ->
53 %% Fine, this should be the case
54 run_listen(GC)
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
55 end.
56
57
58 ctl_args() ->
0be3c7e @klacke untabified all of yaws
authored
59 [{packet, 2},
60 {active, false},
61 binary,
62 {ip, {127,0,0,1}},
63 {reuseaddr, true}].
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
64
65 run_listen(GC) ->
66 case gen_tcp:listen(0, ctl_args()) of
0be3c7e @klacke untabified all of yaws
authored
67 {ok, L} ->
68 case inet:sockname(L) of
69 {ok, {_, Port}} ->
5207102 @klacke Added debug dump functionality
authored
70 %% Need better crypto here
0be3c7e @klacke untabified all of yaws
authored
71 {A1, A2, A3}=now(),
72 random:seed(A1, A2, A3),
73 Key = random:uniform(1 bsl 64),
74 case w_ctl_file(GC#gconf.id, Port, Key) of
75 ok ->
76 proc_lib:init_ack(ok),
77 aloop(L, GC, Key);
78 error ->
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
79 e(
0be3c7e @klacke untabified all of yaws
authored
80 "Failed to create/manipulate the ctlfile ~n"
81 "called ~s~n"
82 "Either problems with permissions or "
83 " earlier runs of yaws ~nwith the same id "
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
84 " <~p> as this, check dir for perms~n",
85 [yaws:ctl_file(GC#gconf.id), GC#gconf.id])
0be3c7e @klacke untabified all of yaws
authored
86 end;
87 Err ->
88 e("Cannot get sockname for ctlsock: ~p",[Err] )
89 end;
90 Err ->
91 e("Cannot listen on ctl socket, fatal: ~p", [Err])
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
92 end.
93
0c9da97 @klacke added ability to run as different user than root
authored
94
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
95 e(Fmt, Args) ->
96 proc_lib:init_ack({error, io_lib:format(Fmt, Args)}),
97 exit(normal).
98
99
100
101 %% write the control file, set perms of the file
102 %% so that only this user can read the file
103 %% That way we're making sure different users
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
104 %% cannot manipulate each others webservers
f4e3e44 @klacke patch by Sergei Golovan which fixed a CGI bug and made yaws_ctl safe
authored
105 w_ctl_file(Sid, Port, Key) ->
106 case catch
0be3c7e @klacke untabified all of yaws
authored
107 begin
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
108 F = yaws:ctl_file(Sid),
109 error_logger:info_msg("Ctlfile : ~s~n", [F]),
0be3c7e @klacke untabified all of yaws
authored
110 file:write_file(F, io_lib:format("~w.", [{Port,Key}])),
111 {ok, FI} = file:read_file_info(F),
112 ok = file:write_file_info(F, FI#file_info{mode = 8#00600})
113 end of
114 {'EXIT', _} ->
115 error;
116 _ ->
117 ok
118 end.
38fb85e @klacke ""
authored
119
120
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
121
f4e3e44 @klacke patch by Sergei Golovan which fixed a CGI bug and made yaws_ctl safe
authored
122 aloop(L, GC, Key) ->
38fb85e @klacke ""
authored
123 case gen_tcp:accept(L) of
0be3c7e @klacke untabified all of yaws
authored
124 {ok, A} ->
125 handle_a(A, GC, Key);
126 Err ->
127 error_logger:format("yaws_ctl failed to accept: ~p~n",
128 [Err]),
129 timer:sleep(2000),
130 ignore
38fb85e @klacke ""
authored
131 end,
f4e3e44 @klacke patch by Sergei Golovan which fixed a CGI bug and made yaws_ctl safe
authored
132 ?MODULE:aloop(L, GC, Key).
38fb85e @klacke ""
authored
133
f4e3e44 @klacke patch by Sergei Golovan which fixed a CGI bug and made yaws_ctl safe
authored
134 handle_a(A, GC, Key) ->
38fb85e @klacke ""
authored
135 case gen_tcp:recv(A, 0) of
0be3c7e @klacke untabified all of yaws
authored
136 {ok, Data} ->
137 case catch binary_to_term(Data) of
138 {hup, Key} ->
139 Res = yaws:dohup(A),
140 Res;
141 {stop, Key} ->
142 gen_tcp:send(A, io_lib:format(
143 "stopping yaws with id=~p\n",
144 [GC#gconf.id])),
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
145 file:delete(yaws:ctl_file(GC#gconf.id)),
0be3c7e @klacke untabified all of yaws
authored
146 init:stop();
147 {{trace, What}, Key} ->
148 Res = actl_trace(What),
149 gen_tcp:send(A, Res),
150 gen_tcp:close(A);
151 {status, Key} ->
152 a_status(A),
153 gen_tcp:close(A);
154 {{load, Mods}, Key} ->
155 a_load(A, Mods),
156 gen_tcp:close(A);
157 {id, Key} ->
158 a_id(A),
159 gen_tcp:close(A);
5207102 @klacke Added debug dump functionality
authored
160 {debug_dump, Key} ->
161 a_debug_dump(A),
162 gen_tcp:close(A);
0be3c7e @klacke untabified all of yaws
authored
163 {Other, Key} ->
164 gen_tcp:send(A, io_lib:format("Other: ~p~n", [Other])),
165 gen_tcp:close(A);
166 _Other ->
167 gen_tcp:close(A)
168
169 end;
170 {error, _} ->
d07115c @klacke Several cleanups due to dialyzer, also moved the control file into us…
authored
171 gen_tcp:close(A)
38fb85e @klacke ""
authored
172 end.
173
6377222 @klacke ""
authored
174
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
175 %% We implement this by reloading a patched config
176 actl_trace(What) ->
177 case lists:member(What, [traffic, http, off]) of
0be3c7e @klacke untabified all of yaws
authored
178 true ->
179 {ok, GC, SCs} = yaws_api:getconf(),
180 case GC#gconf.trace of
181 false when What /= off->
182 yaws_api:setconf(GC#gconf{trace = {true, What}},SCs),
183 io_lib:format(
184 "Turning on trace of ~p to file ~s~n",
185 [What,
186 filename:join([GC#gconf.logdir,
187 "trace." ++ atom_to_list(What)])]);
188 false when What == off ->
189 io_lib:format("Tracing is already turned off ~n",[]);
190 {true, _} when What == off ->
191 yaws_api:setconf(GC#gconf{trace = false},SCs),
192 "Turning trace off \n";
193 {true, What} ->
194 io_lib:format("Trace of ~p is already turned on, ose 'off' "
195 "to turn off~n", [What]);
196 {true, _Other} ->
197 yaws_api:setconf(GC#gconf{trace = {true, What}},SCs),
198 io_lib:format(
199 "Turning on trace of ~p to file ~s~n",
200 [What,
201 filename:join([GC#gconf.logdir,
202 "trace." ++ atom_to_list(What)])])
203 end;
204 false ->
205 "Need either http | traffic | off as argument\n"
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
206 end.
207
208
6377222 @klacke ""
authored
209
210 f(Fmt, As) ->
211 io_lib:format(Fmt, As).
212
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
213
214 a_id(Sock) ->
215 ID = gen_server:call(yaws_server, id, []),
216 gen_tcp:send(Sock, ID),
217 ok.
218
6377222 @klacke ""
authored
219 a_status(Sock) ->
5207102 @klacke Added debug dump functionality
authored
220 gen_tcp:send(Sock, a_status()).
221 a_status() ->
222 try
223 {UpTime, L} = yaws_server:stats(),
224 {Days, {Hours, Minutes, _Secs}} = UpTime,
225 H = f("~n Uptime: ~w Days, ~w Hours, ~w Minutes ~n",
226 [Days, Hours, Minutes]),
227
228 T =lists:map(
229 fun({Host,IP,Hits}) ->
230 L1= f("stats for ~p at ~p ~n",
231 [Host,IP]),
232 T = "\n"
233 "URL Number of hits\n",
234 L2=lists:map(
235 fun({Url, Hits2}) ->
236 f("~-30s ~-7w ~n",
237 [Url, Hits2])
238 end, Hits),
239 END = "\n",
240 [L1, T, L2, END]
241 end, L),
242 [H, T]
243 catch
244 _:Err ->
245 io_lib:format("Cannot get status ~p~n", [Err])
246 end.
247
248
249 a_debug_dump(Sock) ->
250 gen_tcp:send(Sock, a_status()),
251 yaws_debug:do_debug_dump(Sock).
252
6377222 @klacke ""
authored
253
caa1a72 @carsten3347 Added command `-load' to yaws script.
carsten3347 authored
254 a_load(A, Mods) ->
255 case purge(Mods) of
0be3c7e @klacke untabified all of yaws
authored
256 ok ->
257 gen_tcp:send(A, f("~p~n", [loadm(Mods)]));
258 Err ->
259 gen_tcp:send(A, f("~p~n", [Err]))
caa1a72 @carsten3347 Added command `-load' to yaws script.
carsten3347 authored
260 end.
261
262 loadm([]) ->
263 [];
264 loadm([M|Ms]) ->
265 [code:load_file(M)|loadm(Ms)].
266
267 purge(Ms) ->
268 case purge(Ms, []) of
0be3c7e @klacke untabified all of yaws
authored
269 [] -> ok;
270 L -> {cannot_purge, L}
caa1a72 @carsten3347 Added command `-load' to yaws script.
carsten3347 authored
271 end.
272
273 purge([], Ack) ->
274 Ack;
275 purge([M|Ms], Ack) ->
276 case code:soft_purge(M) of
0be3c7e @klacke untabified all of yaws
authored
277 true ->
278 purge(Ms, Ack);
279 false ->
280 purge(Ms, [M|Ack])
caa1a72 @carsten3347 Added command `-load' to yaws script.
carsten3347 authored
281 end.
282
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
283 connect(Sid) ->
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
284 connect_file(yaws:ctl_file(Sid)).
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
285
286
287 %% The ctl file contains the port number the yaws server
f4e3e44 @klacke patch by Sergei Golovan which fixed a CGI bug and made yaws_ctl safe
authored
288 %% is listening at and secret key string.
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
289
290 connect_file(CtlFile) ->
f4e3e44 @klacke patch by Sergei Golovan which fixed a CGI bug and made yaws_ctl safe
authored
291 case file:consult(CtlFile) of
0be3c7e @klacke untabified all of yaws
authored
292 {ok, [{Port, Key}]} ->
293 case gen_tcp:connect({127,0,0,1}, Port,
294 [{active, false},
295 {reuseaddr, true},
296 binary,
297 {packet, 2}], 2000) of
298 {ok, Socket} ->
299 {ok, Socket, Key};
300 Err ->
301 Err
302 end;
303 Err ->
304 Err
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
305 end.
306
307
308
309 actl(SID, Term) ->
310 case connect(SID) of
0be3c7e @klacke untabified all of yaws
authored
311 {error, eaccess} ->
312 io:format("Another user is using the yaws sid <~p>, ~n"
313 "You are not allowd to read the file <~s>, ~n"
314 "specify by <-I id> which yaws system you want "
315 " to control~n",
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
316 [SID, yaws:ctl_file(SID)]),
317 timer:sleep(10),
318 erlang:halt(1);
0be3c7e @klacke untabified all of yaws
authored
319 {error, econnrefused} ->
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
320 io:format("No yaws system responds~n",[]),
321 timer:sleep(10),
322 erlang:halt(2);
0be3c7e @klacke untabified all of yaws
authored
323 {error, Reason} ->
324 io:format("You failed to read the ctlfile ~s~n"
325 "error was: <~p>~n"
326 "specify by <-I id> which yaws system you want "
327 " to control~n",
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
328 [yaws:ctl_file(SID), Reason]),
329 timer:sleep(10),
330 erlang:halt(3);
0be3c7e @klacke untabified all of yaws
authored
331 {ok, Socket, Key} ->
5207102 @klacke Added debug dump functionality
authored
332 gen_tcp:send(Socket, term_to_binary({Term, Key})),
333 Ret = s_cmd(Socket, SID, 0),
334 timer:sleep(40), %% sucks bigtime, we have no good way to flush io
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
335 case Ret of
336 ok ->
337 erlang:halt(0);
338 error ->
339 erlang:halt(4)
340 end
341 end.
38fb85e @klacke ""
authored
342
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
343
5207102 @klacke Added debug dump functionality
authored
344 s_cmd(Fd, SID, Count) ->
345 case gen_tcp:recv(Fd, 0) of
346 {ok, Bin} ->
347 io:format("~s", [binary_to_list(Bin)]),
348 s_cmd(Fd, SID, Count+1);
349 {error, closed} when Count > 0 ->
350 gen_tcp:close(Fd);
351 Err ->
352 io_lib:format("yaws server for yaws id <~p> not "
353 "responding: ~p ~n", [SID, Err]),
354 error
355 end.
356
3dc56a7 @klacke javascript support in ehtml
authored
357
38fb85e @klacke ""
authored
358
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
359 %% List existing yaws nodes on this machine for this user
d659ba3 @klacke added a 'yaws -ls' command that lists all yaws servers on localhost
authored
360 ls(_) ->
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
361 Dir = filename:join([yaws:tmpdir(), "yaws"]),
362 case file:list_dir(Dir) of
0be3c7e @klacke untabified all of yaws
authored
363 {ok, List} ->
364 io:format("~-15s~-10s~-10s~n",
365 ["Id", "Status", "Owner"]),
366 io:format("-------------------------------------~n",[]),
367 lists:foreach(
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
368 fun(IdDir) ->
369 lls(IdDir)
0be3c7e @klacke untabified all of yaws
authored
370 end, List);
371 _ ->
372 ok
373
d659ba3 @klacke added a 'yaws -ls' command that lists all yaws servers on localhost
authored
374 end,
375 init:stop().
6dc4cca @klacke ""
authored
376
377
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
378 lls(IdDir) ->
379 CtlFile = yaws:ctl_file(IdDir),
c9778e0 @klacke added support for 2 additional configure
authored
380 case {file:read_file_info(CtlFile),
0be3c7e @klacke untabified all of yaws
authored
381 file:read_file(CtlFile)} of
382 {{ok, FI}, {error, eacces}} ->
383 User = yaws:uid_to_name(FI#file_info.uid),
384 io:format("~-15s~-10s~-10s~n",
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
385 [IdDir, "noaccess", User]);
0be3c7e @klacke untabified all of yaws
authored
386 {{ok, FI}, {ok, _Bin}} ->
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
387 Running = case connect(IdDir) of
0be3c7e @klacke untabified all of yaws
authored
388 {ok, Sock, _Key} ->
389 gen_tcp:close(Sock),
390 "running";
391 {error, timeout} ->
392 "hanging??";
393 {error, eacces} ->
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
394 "noaccess";
0be3c7e @klacke untabified all of yaws
authored
395 _Err ->
396 "stopped"
397 end,
398 User = yaws:uid_to_name(FI#file_info.uid),
399 io:format("~-15s~-10s~-10s~n",
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
400 [IdDir, Running, User]);
0be3c7e @klacke untabified all of yaws
authored
401 _ ->
402 ok
c105945 @klacke Redid the code which decides where the ctldir resides, now it always …
authored
403 end.
d659ba3 @klacke added a 'yaws -ls' command that lists all yaws servers on localhost
authored
404
0be3c7e @klacke untabified all of yaws
authored
405
6dc4cca @klacke ""
authored
406
38fb85e @klacke ""
authored
407 %% send a hup (kindof) to the yaws server to make it
408 %% reload its configuration and clear its caches
409
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
410 hup([SID]) ->
411 actl(SID, hup).
38fb85e @klacke ""
authored
412
3dc56a7 @klacke javascript support in ehtml
authored
413
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
414 %% stop a daemon
0be3c7e @klacke untabified all of yaws
authored
415 stop([SID]) ->
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
416 actl(SID, stop).
38fb85e @klacke ""
authored
417
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
418 %% query a daemon for status/stats
419 status([SID]) ->
420 actl(SID, status).
421
422 load(X) ->
423 [SID | Modules] = lists:reverse(X),
424 actl(SID, {load, Modules}).
caa1a72 @carsten3347 Added command `-load' to yaws script.
carsten3347 authored
425
6c84378 @klacke ""
authored
426 check([Id, File| IncludeDirs]) ->
92bafb4 @klacke removed the ability change userid, also stopped writing to /tmp/yaws …
authored
427 GC = yaws_config:make_default_gconf(false, undefined),
2f51c68 @klacke -check arg
authored
428 GC2 = GC#gconf{include_dir = lists:map(fun(X) -> atom_to_list(X) end,
0be3c7e @klacke untabified all of yaws
authored
429 IncludeDirs),
430 id = atom_to_list(Id)
431 },
745bb4a @klacke ""
authored
432 yaws_server:setup_dirs(GC2),
9ce9a25 @klacke ""
authored
433 put(sc, #sconf{}),
434 put(gc, GC2),
a7e93df @klacke patch from Magnus froberg to get better control over the files genera…
authored
435 put(use_yfile_name, true),
ef3a52a @klacke Removed the atoms in parse_post and parse query, backwards incompatib…
authored
436 case yaws_compile:compile_file(atom_to_list(File)) of
0be3c7e @klacke untabified all of yaws
authored
437 {ok, [{errors, 0}| _Spec]} ->
438 timer:sleep(100),erlang:halt(0);
439 % init:stop();
440 _Other ->
441 timer:sleep(100),erlang:halt(1)
442 % init:stop()
2f51c68 @klacke -check arg
authored
443 end.
444
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
445 %% control a daemon http/traffic tracer
446 trace([What, SID]) ->
447 actl(SID, {trace, What}).
448
5207102 @klacke Added debug dump functionality
authored
449 debug_dump([SID]) ->
450 actl(SID, debug_dump).
451
38fb85e @klacke ""
authored
452
453
454
0be3c7e @klacke untabified all of yaws
authored
455
456
457
458
38fb85e @klacke ""
authored
459
Something went wrong with that request. Please try again.