2

I have the following code written in Python 2.7 on Windows. I want to check for updates for the current python script and update it, if there is an update, with a new version through ftp server preserving the filename and then executing the new python script after terminating the current through the os.kill with SIGNTERM.

I went with the exit function approach but I read that in Windows this only works with the atexit library and default python exit methods. So I used a combination of the atexit.register() and the signal handler.

***necessary libraries***

filematch = 'test.py'
version = '0.0'
checkdir = os.path.abspath(".")
dircontent = os.listdir(checkdir)
r = StringIO()

def exithandler():
    try:
        try:
            if filematch in dircontent:
                os.remove(checkdir + '\\' + filematch)
        except Exception as e:
            print e

        ftp = FTP(ip address)
        ftp.login(username, password)
        ftp.cwd('/Test')

        for filename in ftp.nlst(filematch):
            fhandle = open(filename, 'wb')
            ftp.retrbinary('RETR ' + filename, fhandle.write)
            fhandle.close()

        subprocess.Popen([sys.executable, "test.py"])
        print 'Test file successfully updated.'
    except Exception as e:
        print e

ftp = FTP(ip address)
ftp.login(username, password)
ftp.cwd('/Test')

ftp.retrbinary('RETR version.txt', r.write)

if(r.getvalue() != version):
    atexit.register(exithandler)
    somepid = os.getpid()
    signal.signal(SIGTERM, lambda signum, stack_frame: exit(1))
    os.kill(somepid, signal.SIGTERM)

print 'Successfully replaced and started the file'

Using the:

signal.signal(SIGTERM, lambda signum, stack_frame: exit(1))

I get:

Traceback (most recent call last):
  File "C:\Users\STiX\Desktop\Python Keylogger\test.py", line 50, in <module>
    signal.signal(SIGTERM, lambda signum, stack_frame: exit(1))
NameError: name 'SIGTERM' is not defined

But I get the job done without a problem except if I use the current code in a more complex script where the script give me the same error but terminates right away for some reason.

On the other hand though, if I use it the correct way, signal.SIGTERM, the process goes straight to termination and the exit function never executed. Why is that?

How can I make this work on Windows and get the outcome that I described above successfully?

3
  • signal.SIGTERM or just 15 should work Commented Jun 8, 2017 at 15:47
  • @Artyer i used that as i mentioned above. The exit function never get executed using signal.SIGTERM for some reason Commented Jun 8, 2017 at 15:51
  • Windows doesn't have POSIX signals. The C runtime implements the 6 required for standard C within the current process, plus nonstandard SIGBREAK. Python's implementation of os.kill on Windows mashes together two completely unrelated functions that don't event target the same thing: GenerateConsoleCtrlEvent (to send a Ctrl+C or Ctrl+Break event to a process group that's attached to the current console) and TerminateProcess to immediately terminate an individual process (like SIGKILL on Unix). Commented Jun 8, 2017 at 20:31

1 Answer 1

0

What you are trying to do seems a bit complicated (and dangerous from an infosec-perspective ;-). I would suggest to handle the reload-file-when-updated part of the functionality be adding a controller class that imports the python script you have now as a module and, starts it and the reloads it when it is updated (based on a function return or other technique) - look this way for inspiration - https://stackoverflow.com/a/1517072/1010991

Edit - what about exe?

Another hacky technique for manipulating the file of the currently running program would be the shell ping trick. It can be used from all programming languages. The trick is to send a shell command that is not executed before after the calling process has terminated. Use ping to cause the delay and chain the other commands with &. For your use case it could be something like this:

import subprocess
subprocess.Popen("ping -n 2 -w 2000 1.1.1.1 > Nul & del hack.py & rename hack_temp.py hack.py & hack.py ", shell=True)

Edit 2 - Alternative solution to original question

Since python does not block write access to the currently running script an alternative concept to solve the original question would be:

import subprocess
print "hello"
a = open(__file__,"r")
running_script_as_string = a.read()
b = open(__file__,"w")
b.write(running_script_as_string)
b.write("\nprint 'updated version of hack'")
b.close()
subprocess.Popen("python hack.py")
Sign up to request clarification or add additional context in comments.

7 Comments

hmm interesting but what if i compile the script into an exe? how am i going to reload the exe after fetching the new one from the ftp server?
That is another question entirely. See updated answer
currently i'm between your suggestions and the os.execl(), since it replaces the current process with the new one. What is your thought? Which one will get the job done (especially for the exe file)?
os.execl seems promising as long as it wold be acceptable to have a new name for the updated .exe file. If you want to keep the same name you would probably have to use the ping trick or similar.
os.execl is almost never something you want to call on Windows. There is nothing like the Unix exec family of system calls in the Windows API, i.e. nothing to replace the contents of a process in place. This call is faked by the C runtime by spawning a new process (with a new PID) and exiting the current process. This signals every handle for the original process. For example, if cmd.exe was waiting for your program to exit, it will assume it's now the foreground process in the console. If your program also uses the console, this will be a mess.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.