Managing software updates for daemons -- ensuring they are not running - macos

I have a general question regarding the right way to do software updates on OS X. My application runs two daemons, both as root. One of the daemons can download the software update package from the network. When downloaded it must install the new binaries, including two binaries replacing the current ones for the daemons. Since both the daemons are currently running, replacing them might be a issue. Hence I have few ideas, however it would helpful to get expert advice on the same.
Method 1: After downloading the update, it can be kept in some location. The update daemon can place a bash script in another specified location and create a plist which can be placed in the LaunchDaemons directory to be triggered during the next reboot. The script simply replaces both the binaries before startup. This is possible only if we can ensure that the two daemons do not start up before my script executes. I didn't find a good way to tell launchd to run my script first, before starting the daemons. So I am not quite sure if this is a good solution.
Method 2: After download, immediately launch a script using launchd programatically. This should be possible, right? The script waits for a TERM signal like shown here https://discussions.apple.com/thread/3636062?start=0&tstart=0 to actually replace the binaries and exit gracefully. Again the problem is, when my script gets launched, I must be sure that my daemons are shut down before replacing the binaries. I am not sure how to do this.
Can anyone suggest which is the better approach and also let me know of any better way?

The solution I use to update daemon is to launch separate shell script which do the next:
unload daemon via launchctl unload -w path.to.plist, it will wait for the job to finish.
remove old files
install new files (here I actually install the package, which will launch my daemon in postflight script)
optional: launch daemon with launchctl load -w path.to.plist
To execute script you need just fork(), setsid() and execv()
You can use applescript in your shell script to gracefully quit application:
osascript << EOF
if application "Your Application" is running then
-- Force application to quit
tell application "Your Application" to quit
-- Wait until it quits
repeat
if application "Your Application" is not running then exit repeat
delay 1
end repeat
end if
EOF
killall -15 your_app # just in case

Related

How do I tell a windows batch script to execute the next line without waiting for the previous line to finish executing?

I'm setting up a .cmd script to be run on startup for a pseudo-server (It's actually a laptop, but that's irrelevant) to automatically launch pageant, load an SSH key, connect to an SSH server using Putty (Pageant would automatically authenticate with the key), then launch mIRC which in turn has a series of scripts setup to operate as an IRC bot and automatically connect to networks using putty as an SSH tunnel.
With that in mind, I have the below code in a startup.cmd file:
"C:\Program Files (x86)\PuTTY\pageant.exe" c:\Path\To\Private\Key.ppk
"C:\Program Files (x86)\PuTTY\putty.exe" -ssh user#host
"C:\Program Files (x86)\mIRC\mirc.exe"
EXIT
When I test run this file, the command prompt runs the first line, launches pageant, and then sits there and does nothing until I close pageant completely. I believe I have an idea on what the issue here is, but I can't find any information on how to resolve this in a batch file.
I do know on linux systems, if I were running a bash script to do something similar, I would want to have a & symbol at the end of each line to tell it to run the next command without waiting for the previous command to finish executing. I did try that in the batch script in the off chance that would work (It didn't).
For those who may ask, this is on Windows 8.1 64 bit. The user running this script is not an administrator.
I can't comment to expand on Squashman's suggestion, so let me answer here.
In your case, if you only want to have Pageant running in the background, without interacting with it, I think it's best to run:
START "" /B <your command>
The /B parameter will spawn the process without launching a new window for it, which seems like something you'd like to avoid (anyway, it's probably closest to the behaviour you can obtain in Linux with &).
Please note that if you close the window from which you spawned this process, it will terminate as well.

How can I launch an AppleScript application and run shell scripts from another AppleScript?

Here are my files:
launcher.applescript
tell application ":path:to:applescript:apps:shell-script-launcher.app" to launch
shell-script-launcher.app [AppleScript, saved as Application]
do shell script "say starting script"
Desired behavior:
Run "launcher.applescript" from AppleScript Editor
Listen for "starting script"
Actual behavior:
Running the "shell-script-launcher.app" by opening it manually in the finder yields expected behavior
Running the "launcher.applescript" opens the "shell-script-launcher.app" but it never executes the shell script.
I've tried saving the app as "Run Only" as well as "Stay Open". Still no progress. What do you recommend. The final result must be an Application instead of an Applescript.
Conceptually:
the run command launches and runs an application hidden
the activate command launches, runs, and activates the application (makes it the frontmost application)
launch, according to Apple, "Launches an application, if it is not already running, but does not send it a run command."
for AppleScript-based applications this should mean that they're loaded, but not executed (i.e., their - implicit or explicit - on run handler is NOT invoked), but in practice that is not true up to 10.9 - see below.
it is unclear (to me) what exactly that means for non-AppleScript-based applications
Here's how Apple thinks it works with AppleScript-based applications, which is only true starting with OSX 10.10 (Yosemite):
A script can send commands to a script application just as it can to other applications. To launch a non-stay-open application and run its script, use a launch command followed by a run command, like this:
launch application "NonStayOpen"
run application "NonStayOpen"
The launch command launches the script application without sending it an implicit run command. When the run command is sent to the script application, it processes the command, sends back a reply if necessary, and quits.
Broken behavior on OSX 10.8, 10.9 (fixed in OSX 10.10):
launch by itself is enough to run the application and is indeed the only command that works with AppleScript-based applications.
Any attempt to execute run or activate (whether in addition to launch or not) runs the application - even twice when run from AppleScript editor(!; just once with osascript) - but reports failure <appName> got an error: Connection is invalid.
This strikes me as bug.
Not sure how OSX versions <= 10.7 behave.
Note: I've witnessed the non-executing behavior with launch once, but every non-stay-open AppleScript-based test app I've created from scratch on OS X 10.9.2 and OS X 10.8.5 also executes the script with launch - contradicting what the documentation says.
Please let me know if your system behaves differently and/or how older versions behave. On what OSX version was the app that doesn't execute with launch created?
On OSX 10.10, behavior is consistent with the documentation, with one thing worth noting:
If the intent is to launch and run in one step, run application is sufficient - no need for a separate launch application command first.
Options
#user309603's pragmatic solution simply uses do shell script with the standard open utility to bypass the problem - this should work, regardless of whether the application is AppleScript-based or not:
do shell script "open " & ¬
quoted form of POSIX path of ¬
alias ":path:to:applescript:apps:shell-script-launcher.app"
If you know the type of application you're invoking up front:
to run an AppleScript-based app: best to use run script file, as #regulus6633 recommends - this has the added advantage that the invoked AppleScript-based application can return objects directly to the caller:
run script file ":path:to:applescript:apps:shell-script-launcher.app"
Note: There's also load script file, which indeed lets you merely load script code without executing it right away.
to run non-AppleScript apps: use run / activate to run the app hidden / frontmost:
run application ":path:to:applescript:apps:shell-script-launcher.app"
You could use run even with AppleScript-based applications and simply ignore errors with try ... end try, as #atonus suggests - the downside is that you won't be able to detect actual failure to invoke the application.
You can mitigate this by selectively ignoring only the specific Connection invalid error (which assumes this error would not legitimately occur) [no longer needed on OSX 10.10]:
try
run application "Macintosh HD:Applications:_Sandbox-AppleScript0.app"
on error number -609 # 'Connection is invalid' error that is spuriously reported
# simply ignore
end try
Finally, on OSX <= 10.9, you could try to simply use the launch command (though that didn't work for the OP, possibly due to working on a <= 10.7 OSX version):
launch application ":path:to:applescript:apps:shell-script-launcher.app"
However, that is not advisable for two reasons:
In OSX 10.10, Apple has fixed the launch behavior to no longer execute also, so your code will break when run there.
While non-AppleScript apps typically do run (hidden) when invoked with launch, the documentation says that AppleScript "does not send it a run command" and "allows you to open an application without performing its usual startup procedures, such as opening a new window" - what that exactly means is not clear and different applications seem to handle this differently.
Applescript has the "run script" command. It works on applescripts or applescript applications. So if I have your app on my desktop then this works...
set appPath to (path to desktop as text) & "shell-script-launcher.app"
run script file appPath
Have you tried open?
do shell script "open 'path/to/applescript/apps/shell-script-launcher.app' && say starting script"
Put it between "try" keywords.
try
tell application ":path:to:applescript:apps:shell-script-launcher.app" to activate
end try
Save your script as an application.
Add the desired script into the Script folder (see path below)
Run as follows, change per type of script you want to run...
property theApplicationPath : the path to me as text <br/>
property theShellScriptPath : theApplicationPath & "Contents:Resources:Scripts:test.command"<br/>
property theShellScript : the quoted form of POSIX path of theShellScriptPath<br/>
<br/>
tell application "Terminal" to (do shell script "/bin/bash " & theShellScript)
<br/>
Boom, Bob's your uncle! At least for me.
It is quite simple, you just have to use the normal do shell script, for example:
do shell script "open " & ¬
quoted form of POSIX path of ¬
alias ":path:to:applescript:apps:shell-script-launcher.app"
This may be helpful but I'm not an expert on this subject. I this case I found the double launching behaviour (on Yosemite, I haven't used any other version of OS X) very annoying and digging around I found one can check if it is already running.
This script is so I can launch a new terminal whenever I like.
if application "Terminal" is running then
tell application "Terminal"
activate
do script ""
end tell
else
tell application "Terminal" to activate
end if

How do I set Terminal scripts to run at start up on Mac OS X Snow Leopard?

Hello I'm using Mac OS X 10.6.8. How can I set some simple Terminal commands to run on start up as if I was opening up Terminal and putting those commands in myself? I basically need to start a few server daemons on start up. The commands I use in Terminal to manually start them look like sudo ruby myrubyserverscript_control.rb start. I apologize in advance if this is super obvious or already answered on here a million times in some way I don't know enough to recognize.
Here are two different things:
you want run a script after the system startup (boot), or
when you logging in
for run a script at boot, you should put one XML config file into /Library/LaunchDaemons (and the launchd process will run the script at the boot time)
for run a script after you logging in - see this: https://stackoverflow.com/a/6445525/632407
Open System Preferences and go to the Users and Groups / Login Items tab. You can add a scipt with the + button or drag it to the list of items. Usually scripts end in .command that are used in this context but they are just bash scripts. I suppose you could use any script that is executable and has the correct #! line.

Starting independent batch files through ssh and process ownership

I've used batch files for many things in the past... but I've always had this problem. I'm sorry if this is a repeat question, I'm not entirely sure I know how to phrase it for searching purposes. The problem is this:
1) Batch file starts some process.
2) command window closed by user.
3) process started by batch file ends.
I imagine this is due to the fact that the started process is "called" by the batch file, and is thus it's child. Specifically what I'm trying to do is login to a server through ssh, run a batch file located on that server which then starts a java program. I need the batch to either stay open, or allow the java program to own itself somehow. That way, when I leave the SSH session, the program will continue to run. Any ideas how I can do this?
I'm running a windows XP x64 server with MobaSSH.
You could try using the psexec tools from sysinternals.
Some possible helpful commands:
at
schtasks
sc
wmic
I'm not sure that any of the above commands will be of any help, but I think they're worth checking out.
Question is not clear, but looks like what you are looking for is a way to "detach" the script from the terminal so that it will continue to run even when the terminal is closed.
You can do:
nohup <your-script> &
Or:
<your-script> &
disown

Mac OS - add app to autostart with launchctl

I can start application with launchctl like this: launchctl submit -l ProgramName -- open -g -b com.company.ProgramName and it works great! I can kill app, and it'll re-run again even if it crashes.
But when i logout or reboot Mac, my process is no longer run. Or, in some cases, it runs not with ProgramName (whitch is my application name), but with name of executable file in ProgramName.app/Contents/MacOS/program_name
Such situation with plist files. I run command launchctl -w /Users/my_username/Library/LaunchAgents and process works fine! But after restart i can't see it.
I prefer first method to load processes, any suggestions why process doesn't autoload after reboot?
I believe you need to set "RunAtLoad" to "true" for it to start your application when user logs in.
But there is no way to set RunAtLoad from command-line when using "submit". At least not in the version of launchctl.c that I checked online.
It looks like you have to create a .plist file with "load", instead of using "submit".
What is more annoying is that launchctl's "load", can not take stdin as input to .plist filename, either with no-argument, or name "-". Shame, perhaps the developers of launchctl are not from Unix background. This means you are forced to litter your short-lived file somewhere on the file-system, at least until you have it loaded.

Resources