Salome HOME
killSalome.py doesn't work with the new portmanager.
[modules/kernel.git] / bin / killSalomeWithPort.py
1 #! /usr/bin/env python
2 #  -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 #
22 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #
24
25 ## \file killSalomeWithPort.py
26 #  Stop all %SALOME servers from given sessions by killing them
27 #
28 #  The sessions are indicated by their ports on the command line as in :
29 #  \code
30 #  killSalomeWithPort.py 2811 2815
31 #  \endcode
32 #
33
34 import os, sys, pickle, signal, commands,glob
35 from salome_utils import verbose
36 import salome_utils
37
38 def getPiDict(port,appname='salome',full=True,hidden=True,hostname=None, with2809pid=False):
39     """
40     Get file with list of SALOME processes.
41     This file is located in the user's home directory
42     and named .<user>_<host>_<port>_SALOME_pidict
43     where
44     <user> is user name
45     <host> is host name
46     <port> is port number
47
48     Parameters:
49     - port    : port number
50     - appname : application name (default is 'SALOME')
51     - full    : if True, full path to the file is returned, otherwise only file name is returned
52     - hidden  : if True, file name is prefixed with . (dot) symbol; this internal parameter is used
53     to support compatibility with older versions of SALOME
54     """
55     from salome_utils import generateFileName, getTmpDir
56     dir = ""
57     if not hostname:
58         hostname = os.getenv("NSHOST")
59         if hostname: hostname = hostname.split(".")[0]
60         pass
61     if full:
62         # full path to the pidict file is requested
63         if hidden:
64             # new-style dot-prefixed pidict files
65             # are in the system-dependant temporary diretory
66             dir = getTmpDir()
67         else:
68             # old-style non-dot-prefixed pidict files
69             # are in the user's home directory
70             dir = os.getenv("HOME")
71             pass
72         pass
73
74     suffix = "pidict"
75     if port == 2809 and with2809pid:
76         suffix = suffix + "-%s"%(os.getpid())
77     return generateFileName(dir,
78                             suffix=suffix,
79                             hidden=hidden,
80                             with_username=True,
81                             with_hostname=hostname or True,
82                             with_port=port,
83                             with_app=appname.upper())
84
85 def appliCleanOmniOrbConfig(port):
86     """
87     Remove omniorb config files related to the port in SALOME application:
88     - ${OMNIORB_USER_PATH}/.omniORB_${USER}_${HOSTNAME}_${NSPORT}.cfg
89     - ${OMNIORB_USER_PATH}/.omniORB_${USER}_last.cfg
90     the last is removed only if the link points to the first file.
91     """
92     from salome_utils import generateFileName, getUserName
93     omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
94     if omniorbUserPath is None:
95         #Run outside application context
96         pass
97     else:
98         omniorb_config      = generateFileName(omniorbUserPath, prefix="omniORB",
99                                                extension="cfg",
100                                                hidden=True,
101                                                with_username=True,
102                                                with_hostname=True,
103                                                with_port=port)
104         last_running_config = generateFileName(omniorbUserPath, prefix="omniORB",
105                                                with_username=True,
106                                                suffix="last",
107                                                extension="cfg",
108                                                hidden=True)
109         if os.access(last_running_config,os.F_OK):
110             if not sys.platform == 'win32':
111                 pointedPath = os.readlink(last_running_config)
112                 if pointedPath[0] != '/':
113                     pointedPath=os.path.join(os.path.dirname(last_running_config), pointedPath)
114                     pass
115                 if pointedPath == omniorb_config:
116                     os.unlink(last_running_config)
117                     pass
118                 pass
119             else:
120                 os.remove(last_running_config)
121                 pass
122             pass
123
124         if os.access(omniorb_config,os.F_OK):
125             os.remove(omniorb_config)
126             pass
127
128         if os.path.lexists(last_running_config):return
129
130         #try to relink last.cfg to an existing config file if any
131         files = glob.glob(os.path.join(omniorbUserPath,".omniORB_"+getUserName()+"_*.cfg"))
132         current_config=None
133         current=0
134         for f in files:
135           stat=os.stat(f)
136           if stat.st_atime > current:
137             current=stat.st_atime
138             current_config=f
139         if current_config:
140           if sys.platform == "win32":
141             import shutil
142             shutil.copyfile(os.path.normpath(current_config), last_running_config)
143             pass
144           else:
145             os.symlink(os.path.normpath(current_config), last_running_config)
146             pass
147           pass
148         pass
149     pass
150
151 ########## kills all salome processes with the given port ##########
152
153 def shutdownMyPort(port, cleanup=True):
154     """
155     Shutdown SALOME session running on the specified port.
156     Parameters:
157     - port - port number
158     """
159     if not port: return
160
161     try:
162         from PortManager import releasePort
163         releasePort(port)
164     except ImportError:
165         pass
166
167     from salome_utils import generateFileName
168
169     # set OMNIORB_CONFIG variable to the proper file
170     omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
171     kwargs = {}
172     if omniorbUserPath is not None:
173         kwargs["with_username"]=True
174     else:
175         omniorbUserPath = os.path.realpath(os.path.expanduser('~'))
176     omniorb_config = generateFileName(omniorbUserPath, prefix="omniORB",
177                                       extension="cfg",
178                                       hidden=True,
179                                       with_hostname=True,
180                                       with_port=port,
181                                       **kwargs)
182     os.environ['OMNIORB_CONFIG'] = omniorb_config
183     os.environ['NSPORT'] = str(port)
184
185     # give the chance to the servers to shutdown properly
186     try:
187         import time
188         from omniORB import CORBA
189         from LifeCycleCORBA import LifeCycleCORBA
190         # shutdown all
191         orb = CORBA.ORB_init([''], CORBA.ORB_ID)
192         lcc = LifeCycleCORBA(orb)
193         lcc.shutdownServers()
194         # give some time to shutdown to complete
195         time.sleep(1)
196         # shutdown omniNames and notifd
197         if cleanup:
198             lcc.killOmniNames()
199             time.sleep(1)
200             pass
201         pass
202     except:
203         pass
204     pass
205
206 def __killMyPort(port, filedict):
207     try:
208         with open(filedict, 'r') as fpid:
209             #
210             from salome_utils import generateFileName
211             if sys.platform == "win32":
212                 username = os.getenv( "USERNAME" )
213             else:
214                 username = os.getenv('USER')
215             path = os.path.join('/tmp/logs', username)
216             fpidomniNames = generateFileName(path,
217                                              prefix="",
218                                              suffix="Pid_omniNames",
219                                              extension="log",
220                                              with_port=port)
221             if not sys.platform == 'win32':
222                 cmd = 'pid=`ps -eo pid,command | egrep "[0-9] omniNames -start %s"` ; echo $pid > %s' % ( str(port), fpidomniNames )
223                 a = os.system(cmd)
224                 pass
225             try:
226                 with open(fpidomniNames) as fpidomniNamesFile:
227                     lines = fpidomniNamesFile.readlines()
228
229                 os.remove(fpidomniNames)
230                 for l in lines:
231                     try:
232                         pidfield = l.split()[0] # pid should be at the first position
233                         if sys.platform == "win32":
234                             import win32pm
235                             if verbose(): print 'stop process '+pidfield+' : omniNames'
236                             win32pm.killpid(int(pidfield),0)
237                         else:
238                             if verbose(): print 'stop process '+pidfield+' : omniNames'
239                             os.kill(int(pidfield),signal.SIGKILL)
240                             pass
241                         pass
242                     except:
243                         pass
244                     pass
245                 pass
246             except:
247                 pass
248             #
249             try:
250                 process_ids=pickle.load(fpid)
251                 for process_id in process_ids:
252                     for pid, cmd in process_id.items():
253                         if verbose(): print "stop process %s : %s"% (pid, cmd[0])
254                         try:
255                             if sys.platform == "win32":
256                                 import win32pm
257                                 win32pm.killpid(int(pid),0)
258                             else:
259                                 os.kill(int(pid),signal.SIGKILL)
260                                 pass
261                             pass
262                         except:
263                             if verbose(): print "  ------------------ process %s : %s not found"% (pid, cmd[0])
264                             pass
265                         pass # for pid, cmd ...
266                     pass # for process_id ...
267                 pass # try...
268             except:
269                 pass
270         # end with
271         #
272         os.remove(filedict)
273         cmd='ps -eo pid,command | egrep "[0-9] omniNames -start '+str(port)+'" | sed -e "s%[^0-9]*\([0-9]*\) .*%\\1%g"'
274         pid = commands.getoutput(cmd)
275         a = ""
276         while pid and len(a.split()) < 2:
277             a = commands.getoutput("kill -9 " + pid)
278             pid = commands.getoutput(cmd)
279             pass
280         pass
281     except:
282         print "Cannot find or open SALOME PIDs file for port", port
283         pass
284     #
285 #
286
287 def killMyPort(port):
288     """
289     Kill SALOME session running on the specified port.
290     Parameters:
291     - port - port number
292     """
293     from salome_utils import getShortHostName, getHostName
294     print "Terminating SALOME on port %s..."%(port)
295
296     # try to shutdown session normally
297     import threading, time
298     threading.Thread(target=shutdownMyPort, args=(port,False)).start()
299     time.sleep(3) # wait a little, then kill processes (should be done if shutdown procedure hangs up)
300
301     try:
302         import PortManager
303         filedict = getPiDict(port, hidden=True, with2809pid=False)
304         import glob
305         all_files = glob.glob("%s*"%filedict)
306         for f in all_files:
307             __killMyPort(port, f)
308     except ImportError:
309         # new-style dot-prefixed pidict file
310         filedict = getPiDict(port, hidden=True)
311         # provide compatibility with old-style pidict file (not dot-prefixed)
312         if not os.path.exists(filedict): filedict = getPiDict(port, hidden=False)
313         # provide compatibility with old-style pidict file (short hostname)
314         if not os.path.exists(filedict): filedict = getPiDict(port, hidden=True,  hostname=getShortHostName())
315         # provide compatibility with old-style pidict file (not dot-prefixed, short hostname)
316         if not os.path.exists(filedict): filedict = getPiDict(port, hidden=False, hostname=getShortHostName())
317         # provide compatibility with old-style pidict file (long hostname)
318         if not os.path.exists(filedict): filedict = getPiDict(port, hidden=True,  hostname=getHostName())
319         # provide compatibility with old-style pidict file (not dot-prefixed, long hostname)
320         if not os.path.exists(filedict): filedict = getPiDict(port, hidden=False, hostname=getHostName())
321         __killMyPort(port, filedict)
322     #
323     appliCleanOmniOrbConfig(port)
324     pass
325
326 def killNotifdAndClean(port):
327     """
328     Kill notifd daemon and clean application running on the specified port.
329     Parameters:
330     - port - port number
331     """
332     try:
333         filedict=getPiDict(port)
334         with open(filedict, 'r') as f:
335             pids=pickle.load(f)
336             for d in pids:
337                 for pid,process in d.items():
338                     if 'notifd' in process:
339                         cmd='kill -9 %d'% pid
340                         os.system(cmd)
341         os.remove(filedict)
342     except:
343       #import traceback
344       #traceback.print_exc()
345       pass
346
347     appliCleanOmniOrbConfig(port)
348
349 def killMyPortSpy(pid, port):
350     dt = 1.0
351     while 1:
352         if sys.platform == "win32":
353             from win32pm import killpid
354             if killpid(int(pid), 0) != 0:
355                 return
356         else:
357             from os import kill
358             try:
359                 kill(int(pid), 0)
360             except OSError, e:
361                 if e.errno != 3:
362                     return
363                 break
364             pass
365         from time import sleep
366         sleep(dt)
367         pass
368     filedict = getPiDict(port, hidden=True)
369     if not os.path.exists(filedict):
370         return
371     try:
372         import omniORB
373         orb = omniORB.CORBA.ORB_init(sys.argv, omniORB.CORBA.ORB_ID)
374         import SALOME_NamingServicePy
375         ns = SALOME_NamingServicePy.SALOME_NamingServicePy_i(orb)
376         import SALOME
377         session = ns.Resolve("/Kernel/Session")
378         assert session
379     except:
380         return
381     try:
382         status = session.GetStatSession()
383     except:
384         # -- session is in naming service but has crash
385         status = None
386         pass
387     if status:
388         if not status.activeGUI:
389             return
390         pass
391     killMyPort(port)
392     return
393
394 if __name__ == "__main__":
395     if len(sys.argv) < 2:
396         print "Usage: "
397         print "  %s <port>" % os.path.basename(sys.argv[0])
398         print
399         print "Kills SALOME session running on specified <port>."
400         sys.exit(1)
401         pass
402     if sys.argv[1] == "--spy":
403         if len(sys.argv) > 3:
404             pid = sys.argv[2]
405             port = sys.argv[3]
406             killMyPortSpy(pid, port)
407             pass
408         sys.exit(0)
409         pass
410     try:
411         from salomeLauncherUtils import setOmniOrbUserPath
412         setOmniOrbUserPath()
413     except Exception, e:
414         print e
415         sys.exit(1)
416     for port in sys.argv[1:]:
417         killMyPort(port)
418         pass
419     pass