This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Espen's profile picture

Prevent Program Termination (Ctrl+T)

Started by Espen, 20 February 2012 - 08:57 PM
Espen #1
Posted 20 February 2012 - 09:57 PM
Why / How does CTRL+T stop my program?
The reason why your programs can be terminated is because you're either using os.pullEvent() somewhere, or because you're calling an external function and that uses os.pullEvent().
os.pullEvent() is the reason why your program will stop execution on pressing CTRL+T:
If you press CTRL+T then the 'terminate' event is created.
os.pullEvent() listens for that event and will throw the error message 'Terminated', which in turn will stop your program.

There are two ways you can prevent CTRL+T from stopping your programs:
  1. Catch the error thrown by os.pullEvent() by making use of the pcall() function.
  2. Quote from lua.org's manual:
    pcall (f, arg1, …)
    Calls function f with the given arguments in protected mode. This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.
    So let's say you have this code:
    
    		local password = "secret"
    		local input
    		
    		repeat
    		  write("Password: ")
    		  input = read()
    		until input == password
    		
    Since read() is using os.pullEvent(), instead of directly calling read() we can call it via pcall() instead:
    
    		local password = "secret"
    		local status, input
    		
    		repeat
    		  write("Password: ")
    		  status, input = pcall(read)
    		until input == password
    		
  3. Use os.pullEventRaw() instead of os.pullEvent()
  4. If you take a closer look at how os.pullEvent() is implemented ("bios.lua"), then you can see that it calls os.pullEventRaw() to receive an event and in addition to that throws an error if the event was 'terminate'. That means instead of using os.pullEvent() in your program, you can just replace it with os.pullEventRaw() to prevent CTRL+T to throw an error. Now, os.pullEventRaw() itself simply wraps coroutine.yield(), but that is not necessary knowledge for this tutorial and deserves its own topic. So if your program is something like this…
    
    		while true do
    		  local sEvent, param = os.pullEvent()
    		
    		  if sEvent == "key" and param == 28 then
    			print("You pressed ENTER")
    		  end
    		end
    		
    … then simply replace the os.pullEvent() with os.pullEventRaw() to prevent CTRL+T from stopping your program:
    
    		while true do
    		  local sEvent, param = os.pullEventRaw()
    		
    		  if sEvent == "key" and param == 28 then
    			print("You pressed ENTER")
    		  end
    		end
    		
    The only way to stop this program now would be to reboot the (ingame-) computer.

But which of all the CC-functions make use of os.pullEvent() ?
As of CC version 1.2 the functions making use of os.pullEvent() either directly or indirectly are:
  • sleep
  • read
  • rednet
So if you're using any of these in your program, it can be stopped by CTRL+T.
To prevent that, call them via pcall (as described further up)

The number of functions using os.pullEvent() or the functions themselves might change in the future though.
Therefore it's always a good idea to check them for yourself. All the functions should either be in "bios.lua" or the API files.
Location of "bios.lua": .minecraft\mods\ComputerCraft\lua\
Location of the API files: .minecraft\mods\ComputerCraft\lua\rom\apis\

Example: Does read() make use of os.pullEvent() ?
  1. read() is defined within "bios.lua", so we open that file.
  2. We search for os.pullEvent() within the read() function and find this line:
    local sEvent, param = os.pullEvent()
  3. So yes, CC's read() does use os.pullEvent() and if we'd use it in our program it could be terminated with CTRL+T.


Further Information:
I hope everything was easy to follow and not too complicated.
If you have any further questions or suggestions, feel free to ask.
Cheers! ;)/>/>
skorbut #2
Posted 29 February 2012 - 03:24 AM
Thanks, helped me alot, is there any chance to prevent CTRL+R ?
Casper7526 #3
Posted 29 February 2012 - 03:54 AM
Nope, CTRL+R and CTRL+S are hardcoded
FuzzyPurp #4
Posted 29 February 2012 - 04:48 AM
There is no reason to prevent that, it's like asking to remove the power/reset button off your computer.
ENET #5
Posted 06 March 2012 - 11:35 PM
Just use this instead.

–At top of program
local oldPull = os.pullEvent;
os.pullEvent = os.pullEventRaw;

–Your program between :unsure:/>/>

–At end of program
os.pullEvent = oldPull;

[[There is no reason to prevent that, it's like asking to remove the power/reset button off your computer]]

Some programs turn redstone on wait awhile and turn it off. Someone can keep it on by shutting it off. There needs to be no way of stopping it, but there should be a way to detect it.
Espen #6
Posted 07 March 2012 - 12:17 AM
@ENET: I'm aware of that, I described it as one possible solution here: http://www.computercraft.info/forums2/index.php?/topic/393-terminate-safe-doublelock/page__view__findpost__p__2514
It's just that I didn't want to include it at the time, because I thought it wouldn't be a good way to go about it in general, but I changed my mind since then.
Whatever makes people's programs work is my philosophy now. At least here. :unsure:/>/>
rex41043 #7
Posted 13 March 2012 - 08:06 AM
RE to:
Casper7526

Posted 29 February 2012 - 04:54 PM
Nope, CTRL+R and CTRL+S are hardcoded

Theres no need if you are doing a password coz u can just code it into the startup file
Mendax #8
Posted 14 March 2012 - 07:08 AM
So, how do I make it print something after pcall? Delete this post if you want.
6677 #9
Posted 14 March 2012 - 02:40 PM
 
--At top of program
local oldPull = os.pullEvent;
os.pullEvent = os.pullEventRaw;

--Your program between :mellow:/>/>

--At end of program
os.pullEvent = oldPull;
 
If I use the above method would this take effect on read etc aswell or would I still need to pcall() them.
Espen #10
Posted 14 March 2012 - 03:19 PM

--At top of program
local oldPull = os.pullEvent;
os.pullEvent = os.pullEventRaw;

--Your program between ;)/>/>

--At end of program
os.pullEvent = oldPull;

If I use the above method would this take effect on read etc aswell or would I still need to pcall() them.
Yes, it takes effect on them, i.e. no need for pcall() when doing it this way. (At least if we're only talking about preventing the terminate event). :mellow:/>/>

All functions which would normally call os.pullEvent(), like e.g. read() or sleep(), will then really call os.pullEventRaw().
This way you don't need to copy stock functions like read() or sleep() and change their code, but just reassign 'pullEvent' to 'pullEventRaw' for the duration of your program.
BlueMond #11
Posted 17 March 2012 - 08:32 PM
There is a reason to want to get rid of ctrl+r and ctrl+s. People can insert a floppy that bypasses ur startup and restart the computer.
Liraal #12
Posted 17 March 2012 - 08:39 PM
not if you place a protected disk drive on top of the computer.
Espen #13
Posted 17 March 2012 - 10:50 PM
Also,
There is a reason to want to get rid of ctrl+r and ctrl+s. People can insert a floppy that bypasses ur startup and restart the computer.
You can protect against that by a one-time change to the bios.lua.
Take a look at the tutorial section, that should point you in the right direction.
BlackRa1n #14
Posted 23 March 2012 - 09:48 PM
How would you use this for 'sleep'?
I typed:

pcall(3)

for sleeping for 3 seconds. I know this is not right, so what do I put?
Liraal #15
Posted 23 March 2012 - 10:07 PM
pcall(sleep,3)
Espen #16
Posted 24 March 2012 - 12:44 AM
How would you use this for 'sleep'?
I typed:

pcall(3)

for sleeping for 3 seconds. I know this is not right, so what do I put?
What Liraal said. :(/>/>

Also you can read up on the definition, which I've linked in the OP.
For your convenience, I'll repost it here: http://www.lua.org/manual/5.1/manual.html#pdf-pcall
You can also look up all kinds of other functions in that manual, as well as decriptions of how things in Lua work in general.
Mind you, not everything works 1:1 in CC, though. But most of it does.
BlackRa1n #17
Posted 24 March 2012 - 08:29 AM
Ok, thanks, both of you! :(/>/>
Espen #18
Posted 24 March 2012 - 12:20 PM
@BlackRa1n:
But remember: pcall only catches an error and thus let's the program continue running.
The sleep function makes use of timers, for which it then waits by listening for incoming events via os.pullEvent()

That means if you use pcall(sleep, 3) and press CTRL+T, then this will cause the os.pullEvent within the sleep function to throw an error.
But instead of our program now terminating, the pcall catches this error and returns control to your program, i.e. the next line after pcall(sleep, 3) is executed.

So with pcall(sleep, 3) you can prevent CTRL+T to terminate your program, but it still would stop the sleep timer prematurely!
That means, if you want to force a specific waiting time on the user, then using pcall() on the sleep function won't ensure that.

To make that happen you would actually have to prevent the os.pullEvent within the sleep function itself to throw an error to begin with.
To achieve that you can backup the global function os.pullEvent and temporarily overwrite it with os.pullEventRaw.
Because the latter won't throw an error on 'terminate' and thus the sleep function won't either (and neither would the read function btw.).

local oldPullEvent = os.pullEvent
os.pullEvent = os.pullEventRaw


After you're done with your program you just restore os.pullEvent with the backup you made at the beginning and then it will behave as it did before again.
os.pullEvent = oldPullEvent

I didn't include this variation at the beginning, because I thought it wasn't good practice. But now I see more and more people ending up having to use it and also it's pretty much required if you use native CC functions which make use of os.pullEvent.
Therefore I might edit the OP to include this sometime this weekend.

Well, hope this was of any use for you, have fun! :(/>/>
BlackRa1n #19
Posted 24 March 2012 - 05:40 PM
@BlackRa1n:
But remember: pcall only catches an error and thus let's the program continue running.
The sleep function makes use of timers, for which it then waits by listening for incoming events via os.pullEvent()

That means if you use pcall(sleep, 3) and press CTRL+T, then this will cause the os.pullEvent within the sleep function to throw an error.
But instead of our program now terminating, the pcall catches this error and returns control to your program, i.e. the next line after pcall(sleep, 3) is executed.

So with pcall(sleep, 3) you can prevent CTRL+T to terminate your program, but it still would stop the sleep timer prematurely!
That means, if you want to force a specific waiting time on the user, then using pcall() on the sleep function won't ensure that.

To make that happen you would actually have to prevent the os.pullEvent within the sleep function itself to throw an error to begin with.
To achieve that you can backup the global function os.pullEvent and temporarily overwrite it with os.pullEventRaw.
Because the latter won't throw an error on 'terminate' and thus the sleep function won't either (and neither would the read function btw.).

local oldPullEvent = os.pullEvent
os.pullEvent = os.pullEventRaw


After you're done with your program you just restore os.pullEvent with the backup you made at the beginning and then it will behave as it did before again.
os.pullEvent = oldPullEvent

I didn't include this variation at the beginning, because I thought it wasn't good practice. But now I see more and more people ending up having to use it and also it's pretty much required if you use native CC functions which make use of os.pullEvent.
Therefore I might edit the OP to include this sometime this weekend.

Well, hope this was of any use for you, have fun! :(/>/>

Thanks! :)/>/>
Alex_ #20
Posted 25 March 2012 - 08:42 PM
Thanks ive got a lot of code to rewrite
Wolvan #21
Posted 25 March 2012 - 09:59 PM
Thanks ive got a lot of code to rewrite
Why not using notepad++'s replace function :o/>/>
sabian8 #22
Posted 01 April 2012 - 09:37 AM
Thanks!, this helped me out a lot.
djblocksaway #23
Posted 06 April 2012 - 01:21 PM
there is about 3 ways to block CTRL+T if you look around you will find other ways :)/>/>
this post is very helpful for people good job
reinei #24
Posted 12 April 2012 - 08:03 PM
And I got the answer why we would want to interrupt Ctrl+S: If I wanted to interrupt it set a variable so it wont get interrupted again and then do some stuff and after all that shutdown. On startup I would unset the variable.
How would I do that?
Advert #25
Posted 12 April 2012 - 09:08 PM
And I got the answer why we would want to interrupt Ctrl+S: If I wanted to interrupt it set a variable so it wont get interrupted again and then do some stuff and after all that shutdown. On startup I would unset the variable.
How would I do that?

You cannot detect CTRL+S or CTRL+R.
sam_technologeek #26
Posted 13 May 2012 - 07:22 PM
Very useful Espen, thanks for the tutorial :P/>/>
Disy #27
Posted 15 July 2012 - 05:49 AM
Sorry to bump this! But I was wondering if there is a way to detect if someone has typed
ctrl+T?
Klausar #28
Posted 21 July 2012 - 07:43 PM
And I got the answer why we would want to interrupt Ctrl+S: If I wanted to interrupt it set a variable so it wont get interrupted again and then do some stuff and after all that shutdown. On startup I would unset the variable.
How would I do that?

You cannot detect CTRL+S or CTRL+R.
Well, couldn't you code that if someone presses CTRL the computer shuts down (Maybe just for startup)?
makerimages #29
Posted 22 July 2012 - 01:25 PM
why do you want to prevent it anyways?
Teraminer #30
Posted 22 July 2012 - 02:00 PM
And I got the answer why we would want to interrupt Ctrl+S: If I wanted to interrupt it set a variable so it wont get interrupted again and then do some stuff and after all that shutdown. On startup I would unset the variable.
How would I do that?

You cannot detect CTRL+S or CTRL+R.
Well, couldn't you code that if someone presses CTRL the computer shuts down (Maybe just for startup)?
Very good idea, I can't think of a way to bypass this!
why do you want to prevent it anyways?
SO none can bypass his door lock or login program.
MysticT #31
Posted 22 July 2012 - 11:26 PM
And I got the answer why we would want to interrupt Ctrl+S: If I wanted to interrupt it set a variable so it wont get interrupted again and then do some stuff and after all that shutdown. On startup I would unset the variable.
How would I do that?

You cannot detect CTRL+S or CTRL+R.
Well, couldn't you code that if someone presses CTRL the computer shuts down (Maybe just for startup)?
So you avoid the user shuting down the computer by shuting it down?
Klausar #32
Posted 23 July 2012 - 07:31 PM
Of course you could use something different like os.shutdown()
Noodle #33
Posted 24 July 2012 - 03:32 AM
You couldn't avoid the user doing CTRL + R / CTRL + S.
You can slow it down by detecting the keys s, ctrl, and r, and making it so it says NO SHUTTING DOWN or something like that.
Darky_Alan #34
Posted 24 July 2012 - 09:03 AM
This is a nice post, all I'd do was switch out

os.pullEvent = os.pullEventRaw

with a third random variable in a local function, this gave me a better understanding of how event work. thanks man.
oasis9 #35
Posted 28 November 2012 - 08:58 PM
I have a lockdown program that can be bypassed and my logging system will be run again when the computer is restarted, so you can skip the holdup, that is supposed to deter you from finding the code, all you have to do is ctrl+r or ctrl+s.
Espen #36
Posted 28 November 2012 - 09:36 PM
@oasis9:
I'm not sure I follow you. You say you have a lockdown program that can be bypassed and then go on to say that one can skip program termination by rebooting.
But if you don't secure your lockdown program from termination, then that's to be expected.
Or what exactly do you mean? :huh:/>
KaoS #37
Posted 28 November 2012 - 11:18 PM
from what I can see if you guess his password wrong it locks the PC for a while so you cannot brute force or guess… when this happens you can just restart the PC

There is no way to stop people from restarting your PC, what I would do is make a file when you start lockdown, when the computer starts up if that file exists then lockdown again
Espen #38
Posted 29 November 2012 - 02:15 AM
from what I can see if you guess his password wrong it locks the PC for a while so you cannot brute force or guess… when this happens you can just restart the PC

There is no way to stop people from restarting your PC, what I would do is make a file when you start lockdown, when the computer starts up if that file exists then lockdown again
I see, that makes much more sense, lol.^^
I'm so used to "logging" being a recording for program activities that I didn't see he actually meant a login system.
Misunderstanding, my bad. Thanks for clearing that up.

Regarding the problem described:
Writing to a file would definitely be a good solution, I agree.
When he wants to permanently lock down the computer, then he could also e.g. write os.shutdown() into the startup file.
ChunLing #39
Posted 30 November 2012 - 12:22 PM
It would be more useful to shut the computer down and then "reboot" for a long period of time, with a loop that counted off the amount of time left to reboot. All Ctrl+S/R would accomplish in that case would be restarting the "leave me the *&%( alone, you rebooter" timeout.

Of course, eventually they'd break the computer so you have to have a deathtrap setup for when they do that. Better yet, the deathtrap is activated the moment the computer boots, but they're still in the console, not noticing the giant lavafall.
xxxredportalxxx #40
Posted 16 January 2013 - 07:43 PM
Thank you this code has been very usefull ;)/>
fodakahn #41
Posted 04 February 2013 - 12:15 PM
This was really helpful! Now noone can get into my computer lab through the passworded door but ME! :)/>
Hanse00 #42
Posted 04 February 2013 - 11:32 PM
Is there any way to stop the computer from booting from a disk drive?

(Note: I'm doing this on a server, so I don't really think I can edit any of the os files)
theoriginalbit #43
Posted 05 February 2013 - 12:01 AM
Is there any way to stop the computer from booting from a disk drive?

(Note: I'm doing this on a server, so I don't really think I can edit any of the os files)
No.

As Espen said below it can be done through means other than code.

It was also discovered by a user the other week that boot order starts with the top. so placing your own drive with a startup disk on the top would supersede all other drives.
Espen #44
Posted 05 February 2013 - 12:36 AM
Is there any way to stop the computer from booting from a disk drive?

(Note: I'm doing this on a server, so I don't really think I can edit any of the os files)
Well not implicitly, but you could work around it by exposing only one block-face of the computer to the outside.
This way someone could only put a disk-block directly infront of the computer, but this would block access to the computer and the attacker wouldn't be able to turn it on.

Securing it this way only works if nobody is allowed/able to break blocks around your computer, or if no peripheral is installed which would allow other methods of circumvention (like e.g. peripheral-cables).
Skullblade #45
Posted 05 February 2013 - 01:28 AM
If you have red power you could also put a cover on one of the corners so nothing can b placed right there…
DiamondOwner #46
Posted 05 February 2013 - 03:25 PM
I have an idea of how to stop CTRL+R/S. Here's the code.

os.pullEvent=os.pullEventRaw
parallel(prevent, ***place other functions here***)
function prevent()
local key, control=os.pullEvent("key")
if control==29 or control==157 then
	   print("Ctrl commands are locked.")
       sleep(2)
	   shell.run("***place the program name of the program containing this code***")
end
DiamondOwner #47
Posted 05 February 2013 - 03:28 PM
Espen, I think I found a flaw to your plan. If someone(Person 1) has opened the computer and someone else(Person 2) places the disk drive. That someone else(Person 2) can insert the floppy disk, while the someone(Person 1) can reboot the computer.
theoriginalbit #48
Posted 05 February 2013 - 03:30 PM
I have an idea of how to stop CTRL+R/S. Here's the code.

os.pullEvent=os.pullEventRaw
parallel(prevent, ***place other functions here***)
function prevent()
local key, control=os.pullEvent("key")
if control==29 or control==157 then
	   print("Ctrl commands are locked.")
	   sleep(2)
	   shell.run("***place the program name of the program containing this code***")
end
Wont work. Ctrl + R/S are done Java side of the mod, not Lua. So sleeping does nothing

Espen, I think I found a flaw to your plan. If someone(Person 1) has opened the computer and someone else(Person 2) places the disk drive. That someone else(Person 2) can insert the floppy disk, while the someone(Person 1) can reboot the computer.
Or (person 1) turn off the computer, (person 1) places disk drive, (person 1) places disk, (person 1) turns on computer. Done. There is no way to be 100% secure, but there are many methods to remove all the ways that are possible to remove. So whenever a computer is on you can eject the disk and stopping ctrl+t that pretty much all you can do.
Espen #49
Posted 05 February 2013 - 08:33 PM
Espen, I think I found a flaw to your plan. If someone(Person 1) has opened the computer and someone else(Person 2) places the disk drive. That someone else(Person 2) can insert the floppy disk, while the someone(Person 1) can reboot the computer.
Yes, someone could be sneaky like that, that's why I'd make sure that whenever I want to start/restart a computer nobody else is around.
If there is someone around and I decide to trust him, just to have him trick me, then you can sure as hell believe he's going to respawn a few seconds later. ;)/>

But yeah, as long as a computer can boot from disk, it will. So there's no perfect way to prevent that from happening except for making sure the computer itself is not accessible by anyone else but yourself (i.e. locking it away somehow).

If you have access to the bios.lua though, then you can modify its disk-boot behaviour and either turn it off completely, require a password for disk-booting, or simply print out a message whenever a disk-boot occurs.
You can even modify it in such a way that you can set disk-boot policies per computer (via IDs or similar).

If you don't have access to the bios.lua, then you could make the necessary modifications and pitch them to the server owner.
If he's knowledgeable enough in Lua and thinks the code is legit, without any deviousness or errors, then he can replace the bios.lua for you.
But if he isn't or doesn't trust you, then there's not much that can be done about it though. ^^
Hanse00 #50
Posted 06 February 2013 - 01:51 AM
So the most secure seems to be (assuming other players can't break your blocks, in which case a door is pointless in the first place)
  • Only allow one face of the computer to be accessible
  • Put your program on a disk as startup, place this in a disk drive above the computer
  • Make sure the program can't be terminated
A few more that I came up with for myself (for use as a secure door
  • Use two computers (that way if somebody somehow does access the terminal, even if it should be impossible, that computer doesn't store the password for the door)
  • Connect them via cables (So people can't put down a "spy" computer listening in on my rednet messages)
This way I have computer A send whatever you input to computer B (hidden somewhere completely inaccessible), computer B opens the door if the password is right.
Dlcruz129 #51
Posted 06 February 2013 - 04:21 AM
You can't listen in on rednet.send() messages.
theoriginalbit #52
Posted 06 February 2013 - 04:27 AM
So the most secure seems to be (assuming other players can't break your blocks, in which case a door is pointless in the first place)
  • Only allow one face of the computer to be accessible
  • Put your program on a disk as startup, place this in a disk drive above the computer
  • Make sure the program can't be terminated
A few more that I came up with for myself (for use as a secure door
  • Use two computers (that way if somebody somehow does access the terminal, even if it should be impossible, that computer doesn't store the password for the door)
  • Connect them via cables (So people can't put down a "spy" computer listening in on my rednet messages)
This way I have computer A send whatever you input to computer B (hidden somewhere completely inaccessible), computer B opens the door if the password is right.
Yes pretty much, although I would have rednet instead of a cable, a cable output can be faked, if you program right, only the computer that should be telling it stuff through rednet it will do actions for. The terminal the player uses would be the fake one that just sends the password to the main one to validate. so really there wouldn't even need to be a disk drive on the top of this one.
DiamondOwner #53
Posted 06 February 2013 - 09:14 AM
theOriginalBIT, I usually do that for my login systems. I make a computer that sends strings to the login computer. The login computer checks if the username and password is correct. The login then sends info to the main computer, to open the door.