Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 389 lines (309 sloc) 8.843 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 -compile(export_all).
15 -include_lib("kernel/include/file.hrl").
2f51c68 @klacke -check arg
authored
16 -include_lib("yaws/include/yaws.hrl").
17 -include_lib("yaws/include/yaws_api.hrl").
28e4c73 @klacke first attempt to run properly under cygwin
authored
18 -include("yaws_debug.hrl").
2f51c68 @klacke -check arg
authored
19
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
20
21
22 %% assumes the appropriate file structures
23 %% are already created with the right perms
24
25 start(GC, FirstTime) when FirstTime == false ->
26 ok;
27 start(GC, true) ->
28 case proc_lib:start_link(?MODULE, run, [GC]) of
29 ok ->
30 ok;
31 {error, RSN} ->
32 error_logger:format("~s~n",[RSN]),
33 exit(RSN)
28e4c73 @klacke first attempt to run properly under cygwin
authored
34 end.
35
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
36
37 %% syncronous start,
38 %% If we're later supposed
39 %% to change uid, we're still root here.
40
41 run(GC) ->
42 %% First check if there is already a Yaws system running
43 %% with the same sid.
44
45 case connect(GC#gconf.id) of
46 {ok, Sock} ->
47
48 %% Not good, let's get some sys info
49 %% from that system so we can produce a good error
50 %% message
51 gen_tcp:close(Sock),
52 e("There is already a yaws system running with the same ~n"
53 " id <~p> on this computer, ~n"
54 " set another id in the yaws conf file ~n",
55 [GC#gconf.id]);
56 {error, eaccess} ->
57 %% We're not allowed to open the ctl file
58 e("Error reading ~s, you are probably (sometimes) running ~n"
59 " yaws as another userid, but with the same yaws id <~p> ~n"
60 " set another id in the yaws conf file ~n",
61 [ctl_file(GC#gconf.id), GC#gconf.id]);
62 {error, _} ->
63 %% Fine, this should be the case
64 run_listen(GC)
65 end.
66
67
68 ctl_args() ->
69 [{packet, 2},
70 {active, false},
71 binary,
72 {ip, {127,0,0,1}},
73 {reuseaddr, true}].
74
75 run_listen(GC) ->
76 case gen_tcp:listen(0, ctl_args()) of
38fb85e @klacke ""
authored
77 {ok, L} ->
78 case inet:sockname(L) of
79 {ok, {_, Port}} ->
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
80 case w_ctl_file(GC#gconf.id,Port) of
81 ok ->
82 proc_lib:init_ack(ok),
83 aloop(L, GC);
84 error ->
85 e("Failed to create/manipulate the ctlfile ~n"
86 "called ~s~n"
87 "either problems with permissions or "
88 " earlier runs of yaws ~nwith the same id "
89 " <~p> as this, check /tmp/yaws/* for perms~n",
90 [ctl_file(GC#gconf.id), GC#gconf.id])
91 end;
0c9da97 @klacke added ability to run as different user than root
authored
92 Err ->
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
93 e("Cannot get sockname for ctlsock: ~p",[Err] )
38fb85e @klacke ""
authored
94 end;
0c9da97 @klacke added ability to run as different user than root
authored
95 Err ->
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
96 e("Cannot listen on ctl socket, fatal: ~p", [Err])
97 end.
98
0c9da97 @klacke added ability to run as different user than root
authored
99
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
100 e(Fmt, Args) ->
101 proc_lib:init_ack({error, io_lib:format(Fmt, Args)}),
102 exit(normal).
103
104
105
106 %% write the control file, set perms of the file
107 %% so that only this user can read the file
108 %% That way we're making sure different users
109 %% cannot manipulate eachothers webservers
110 w_ctl_file(Sid, Port) ->
111 case catch
112 begin
113 F = ctl_file(Sid),
114 ?Debug("Ctlfile : ~s~n", [F]),
115 file:write_file(F, io_lib:format("~w", [Port])),
116 {ok, FI} = file:read_file_info(F),
117 ok = file:write_file_info(F, FI#file_info{mode = 8#00600})
118 end of
119 {'EXIT', _} ->
120 error;
121 _ ->
122 ok
38fb85e @klacke ""
authored
123 end.
124
125
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
126 ctl_file(Sid) ->
127 filename:join([yaws:tmp_dir(),
128 "yaws",
129 Sid,
130 "ctl"]).
131
132
133
134 aloop(L, GC) ->
38fb85e @klacke ""
authored
135 case gen_tcp:accept(L) of
136 {ok, A} ->
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
137 handle_a(A, GC);
2129adc @klacke ""
authored
138 _Err ->
38fb85e @klacke ""
authored
139 ignore
140 end,
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
141 ?MODULE:aloop(L, GC).
38fb85e @klacke ""
authored
142
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
143 handle_a(A, GC) ->
38fb85e @klacke ""
authored
144 case gen_tcp:recv(A, 0) of
145 {ok, Data} ->
146 case binary_to_term(Data) of
147 hup ->
50a7ab2 @klacke added support/docs for embedded mode
authored
148 Res = yaws:dohup(A),
149 Res;
38fb85e @klacke ""
authored
150 stop ->
6377222 @klacke ""
authored
151 gen_tcp:send(A, "stopping\n"),
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
152 file:delete(ctl_file(GC#gconf.id)),
38fb85e @klacke ""
authored
153 init:stop();
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
154 {trace, What} ->
155 Res = actl_trace(What),
156 gen_tcp:send(A, Res),
157 gen_tcp:close(A);
6377222 @klacke ""
authored
158 status ->
50a7ab2 @klacke added support/docs for embedded mode
authored
159 a_status(A),
160 gen_tcp:close(A);
caa1a72 @carsten3347 Added command `-load' to yaws script.
carsten3347 authored
161 {load, Mods} ->
162 a_load(A, Mods),
163 gen_tcp:close(A);
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
164 id ->
165 a_id(A),
166 gen_tcp:close(A);
50a7ab2 @klacke added support/docs for embedded mode
authored
167 Other ->
168 gen_tcp:send(A, io_lib:format("Other: ~p~n", [Other])),
169 gen_tcp:close(A)
170
171 end;
2129adc @klacke ""
authored
172 _Err ->
38fb85e @klacke ""
authored
173 ignore
174 end.
175
6377222 @klacke ""
authored
176
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
177 %% We implement this by reloading a patched config
178 actl_trace(What) ->
179 case lists:member(What, [traffic, http, off]) of
180 true ->
181 {ok, GC, SCs} = yaws_api:getconf(),
182 case GC#gconf.trace of
183 false when What /= off->
184 yaws_api:setconf(GC#gconf{trace = {true, What}},SCs),
185 io_lib:format(
186 "Turning on trace of ~p to file ~s~n",
187 [What,
188 filename:join([GC#gconf.logdir,
189 "trace." ++ atom_to_list(What)])]);
190 false when What == off ->
191 io_lib:format("Tracing is already turned off ~n",[]);
192 {true, _} when What == off ->
193 yaws_api:setconf(GC#gconf{trace = false},SCs),
194 "Turning trace off \n";
195 {true, What} ->
196 io_lib:format("Trace of ~p is already turned on, ose 'off' "
197 "to turn off~n", [What]);
198 {true, Other} ->
199 yaws_api:setconf(GC#gconf{trace = {true, What}},SCs),
200 io_lib:format(
201 "Turning on trace of ~p to file ~s~n",
202 [What,
203 filename:join([GC#gconf.logdir,
204 "trace." ++ atom_to_list(What)])])
205
206
207 end;
208 false ->
209 "Need either http | traffic | off as argument\n"
210 end.
211
212
6377222 @klacke ""
authored
213
214 f(Fmt, As) ->
215 io_lib:format(Fmt, As).
216
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
217
218 a_id(Sock) ->
219 ID = gen_server:call(yaws_server, id, []),
220 gen_tcp:send(Sock, ID),
221 ok.
222
223
6377222 @klacke ""
authored
224 a_status(Sock) ->
225 {UpTime, L} = yaws_server:stats(),
a7ac905 @klacke introduced opaque data in sconf
authored
226 {Days, {Hours, Minutes, _Secs}} = UpTime,
6377222 @klacke ""
authored
227 H = f("~n Uptime: ~w Days, ~w Hours, ~w Minutes ~n",
228 [Days, Hours, Minutes]),
229
230 T =lists:map(
231 fun({Host,IP,Hits}) ->
232 L1= f("stats for ~p at ~p ~n",
233 [Host,IP]),
234 T = "\n"
235 "URL Number of hits\n",
236 L2=lists:map(
237 fun({Url, Hits2}) ->
238 f("~-30s ~-7w ~n",
239 [Url, Hits2])
240 end, Hits),
241 END = "\n",
242 [L1, T, L2, END]
243 end, L),
8722844 @klacke a file which has at least one compilation error shouldn't be cached i…
authored
244 gen_tcp:send(Sock, [H, T]),
245
246 %% Now lets' figure out the status of loaded modules
247 ok.
6377222 @klacke ""
authored
248
caa1a72 @carsten3347 Added command `-load' to yaws script.
carsten3347 authored
249 a_load(A, Mods) ->
250 case purge(Mods) of
251 ok ->
252 gen_tcp:send(A, f("~p~n", [loadm(Mods)]));
253 Err ->
254 gen_tcp:send(A, f("~p~n", [Err]))
255 end.
256
257 loadm([]) ->
258 [];
259 loadm([M|Ms]) ->
260 [code:load_file(M)|loadm(Ms)].
261
262 purge(Ms) ->
263 case purge(Ms, []) of
264 [] -> ok;
265 L -> {cannot_purge, L}
266 end.
267
268 purge([], Ack) ->
269 Ack;
270 purge([M|Ms], Ack) ->
271 case code:soft_purge(M) of
272 true ->
273 purge(Ms, Ack);
274 false ->
275 purge(Ms, [M|Ack])
276 end.
277
278
3dc56a7 @klacke javascript support in ehtml
authored
279
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
280 connect(Sid) ->
281 connect_file(ctl_file(Sid)).
282
283
284 %% The ctl file contains the port number the yaws server
285 %% is listening at.
286
287 connect_file(CtlFile) ->
3dc56a7 @klacke javascript support in ehtml
authored
288 case file:read_file(CtlFile) of
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
289 {ok, Bin} ->
290 L = binary_to_list(Bin),
38fb85e @klacke ""
authored
291 I = list_to_integer(L),
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
292 gen_tcp:connect({127,0,0,1}, I,
293 [{active, false},
294 {reuseaddr, true},
295 binary,
296 {packet, 2}]);
38fb85e @klacke ""
authored
297 Err ->
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
298 Err
299 end.
300
301
302
303 actl(SID, Term) ->
304 case connect(SID) of
305 {error, eaccess} ->
306 io:format("Another user is using the yaws sid <~p>, ~n"
307 "You are not allowd to read the file <~s>, ~n"
308 "specify by <-I id> which yaws system you want "
309 " to control~n",
310 [SID, ctl_file(SID)]);
311 {error, econnrefused} ->
312 io:format("No yaws system responds~n",[]);
313 {error, Reason} ->
314 io:format("You failed to read the ctlfile ~s~n"
315 "error was: <~p>~n"
316 "specify by <-I id> which yaws system you want "
317 " to control~n",
318 [ctl_file(SID), Reason]);
319 {ok, Socket} ->
320 Str = s_cmd(Socket, SID, Term),
321 io:format("~s", [Str])
38fb85e @klacke ""
authored
322 end,
323 init:stop().
324
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
325
326 s_cmd(Fd, SID, Term) ->
327 gen_tcp:send(Fd, term_to_binary(Term)),
328 Res = case gen_tcp:recv(Fd, 0) of
329 {ok, Bin} ->
330 binary_to_list(Bin);
331 Err ->
332 io_lib:format("yaws server for yaws id <~p> not "
333 "responding: ~p ~n", [SID, Err])
334 end,
335 gen_tcp:close(Fd),
336 Res.
3dc56a7 @klacke javascript support in ehtml
authored
337
38fb85e @klacke ""
authored
338
339 %% send a hup (kindof) to the yaws server to make it
340 %% reload its configuration and clear its caches
341
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
342 hup([SID]) ->
343 actl(SID, hup).
38fb85e @klacke ""
authored
344
3dc56a7 @klacke javascript support in ehtml
authored
345
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
346 %% stop a daemon
347 stop([SID]) ->
348 actl(SID, stop).
38fb85e @klacke ""
authored
349
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
350 %% query a daemon for status/stats
351 status([SID]) ->
352 actl(SID, status).
353
354 load(X) ->
355 [SID | Modules] = lists:reverse(X),
356 actl(SID, {load, Modules}).
caa1a72 @carsten3347 Added command `-load' to yaws script.
carsten3347 authored
357
2f51c68 @klacke -check arg
authored
358 check([File| IncludeDirs]) ->
359 GC = yaws_config:make_default_gconf(false),
360 GC2 = GC#gconf{include_dir = lists:map(fun(X) -> atom_to_list(X) end,
361 IncludeDirs)},
362 SC = #sconf{},
12cb27f @klacke ""
authored
363
ef3a52a @klacke Removed the atoms in parse_post and parse query, backwards incompatib…
authored
364 case yaws_compile:compile_file(atom_to_list(File)) of
06a1bef @klacke ""
authored
365 {ok, [{errors, 0}| _Spec]} ->
2f51c68 @klacke -check arg
authored
366 io:format("ok~n",[]),
367 init:stop();
06a1bef @klacke ""
authored
368 _Other ->
12cb27f @klacke ""
authored
369 io:format("~nErrors in ~p~n", [File]),
2f51c68 @klacke -check arg
authored
370 init:stop()
371 end.
372
dc00e52 @klacke postvar bug by hal snyder, added yaws_api:query_url/1 added the id su…
authored
373 %% control a daemon http/traffic tracer
374 trace([What, SID]) ->
375 actl(SID, {trace, What}).
376
2f51c68 @klacke -check arg
authored
377
378
38fb85e @klacke ""
authored
379
380
381
382
383
384
385
386
387
388
Something went wrong with that request. Please try again.