You are not logged in.
Pages: 1
I am trying to emulate the behaviour of the old rc.local. What I want is a systemd service file that is part of the multi-user.target and is run after everything else. I do not see how to implement this.
Last edited by olive (2014-10-09 19:47:28)
Offline
I think your only option anymore is to write a custom .service file.
But whether the Constitution really be one thing, or another, this much is certain - that it has either authorized such a government as we have had, or has been powerless to prevent it. In either case, it is unfit to exist.
-Lysander Spooner
Offline
I think your only option anymore is to write a custom .service file.
But how can I tell systemd to run it after everything else in multi-user.target?. I can't say
After=multi-user.target
Because it would mean to launch the service after itself.
Offline
I guess you'd need to associate it with a target that is configured as After=multi-user.target . The only standard target with that requirement is
$ cat /usr/lib/systemd/system/graphical.target
...
Requires=multi-user.target
After=multi-user.target
Maybe it's better practice to associate it with a custom target ( rc-local.target ) though.
OTOH this could be an XYZ-problem. Maybe you should elaborate on exactly what you're trying to do.
Last edited by alphaniner (2014-10-09 20:56:10)
But whether the Constitution really be one thing, or another, this much is certain - that it has either authorized such a government as we have had, or has been powerless to prevent it. In either case, it is unfit to exist.
-Lysander Spooner
Offline
I agree, this sounds like an XY(Z) problem. Perhaps you want a user session. Otherwise why does this have to be after everything else? Certainly there are just certain things you want it to be after; use those as After= lines.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
I agree, this sounds like an XY(Z) problem. Perhaps you want a user session. Otherwise why does this have to be after everything else? Certainly there are just certain things you want it to be after; use those as After= lines.
What I want to have is a generic script that is ready to accept my custom commands to be startup at boot. The aim is to set a service one for all and not to have to write a new service file each time. Some people may tell that is not clean but I disagree. It is not clean if you want to make such startup command part of Linux distribution but to manage a specific machine, I need something quicker than writing a new service with the optimal dependencies each time.
Offline
Why not just start the service from your xinitrc shell rc, or something like that? Or for that matter, just source/call your rc.local script from your shellrc or xinitrc. It sounds like you are sold on using a systemd service file, but you want it to not act at all like a systemd service file.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
This is what I have done
$ cat /etc/systemd/system/mylocal.service
[Unit]
Description=My local script
After=network.target
[Service]
ExecStart=/usr/bin/myrc.local
Type=forking
[Install]
WantedBy=multi-user.target
TIP: WantedBy makes it part of multi-user.target.
Now find the last thing that is run in multi-user.target
Say by running:
systemd-analyze plot
journalctl
systemd-analyze critical-chain
Change After=XYZ.service in above code accordingly
Do not forget to run:
systemctl enable mylocal.service
systemctl daemon-reload
Last edited by amish (2014-10-10 02:12:59)
Offline
The answer of my original question appear to be more complicated that what I thought. Indeed Google has not been my friend either. I thought there was an easy way to specify that this service should be run at the latest but maybe not. Trying to find the latest thing with systemd-analyze critical-chain is not robust because it depends of the current configuration of the systemd services. It can break if I change the services to be run. But I think I will use the amish solution (thanks!) and simply say After=network.target. The essential part of multi-user.target should be up after network, this offers a good workaround.
Last edited by olive (2014-10-10 07:17:13)
Offline
What you can do is, assume that all services under multi-user.target will end / complete within 60 seconds.
In your myrc.local, put first statement as "sleep 60"
This will indirectly run your actual script at the end of all of other multi-user services
Since it is under "forking" mode It will not delay your boot.
Last edited by amish (2014-10-10 07:45:50)
Offline
I agree, this sounds like an XY(Z) problem.
Yup, and the one thing we haven't seen here yet is an explanation of what this script does. The OP obviously assumes that what the script does influences when it should be executed, but hasn't actually shared what the script does.
The answer of my original question appear to be more complicated that what I thought.
It may not be. The foundation of every X-Y problem is that the user is convinced that their first idea must be the correct one, when alternatives may exist. You might just be set on doing something a certain way because you think it's the only way, when it may actually not be. That's why you should always share as much detail about your intended goal as possible.
Offline
Isn't it possible to just set After=multi-user.target?
PD: sorry if this doesn't work, systemd noob here. Just a shot in the dark.
Last edited by Pse (2014-10-12 03:19:18)
Offline
After multi-user target means it has to be part of graphical.target and graphic mode should have been enabled.
Otherwise it wont run.
Offline
After multi-user target means it has to be part of graphical.target and graphic mode should have been enabled.
Otherwise it wont run.
I don't follow. Why would it have to be part of graphical.target. And what does that even mean, "be part of"?
I can't think of a reason why it would not work. Ordering (Before/After) and requirement dependencies (Wantedby etc.) are independent.
Since it is under "forking" mode It will not delay your boot.
Only if it actually forks, right? systemd waits for the ExecStart process to exit, so if you're lying about the forking, it would still hang for a while. You could also try Type=idle, at least compared to `sleep 60` that seems cleaner (if After=multi-user.target really is not an option).
Offline
Well if service is part of target i.e. WantedBy (in this case multi-user.target)
And if u say After=multi-user.target.
I suppose it becomes ambiguous.
Because multi-user.target will not be considered as complete till that service is over.
But then we tell dont start till multi-user target is over!
Its ambiguous but may be systemd is smart to detect this ambiguity and assume that user wants service to run at end.
About forking - yes process should fork and exit.
I never tried Type=idle and I could not understand man page decscription of Idle. (Idle is similar to oneshot)
I suggested forking because forking does not kill background processes.
My script was putting some processes in background. When I used Type=Oneshot, the background processes would get killed once main script ends.
So thats why I use Type=forking in which case background processes continue to run even after main script ended.
Offline
Yes then the forking makes sense. As for the ordering, it still sounds like you're only "supposing" it will not work.
Offline
Did you try alphaniner's suggestion of a custom target? IMO, this is the right answer.
Something like:
# /etc/systemd/system/custom-system.target
[Unit]
Description=Custom System Target
Requires=multi-user.target
Conflicts=rescue.service rescue.target
After=multi-user.target
AllowIsolate=yes
Then set it as the default boot target:
systemctl set-default custom-system.target
Then you can write a custom service file:
# /etc/systemd/system/rc-local.service
[Unit]
Description=Custom rc-local Launcher
After=multi-user.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/rc-local
ExecStop=/etc/rc-local-cleanup
[Install]
WantedBy=custom-system.target
Offline
@branch. Having a whole new target just for the purpose of running a single script is a little overkill. I will work but you also need to be careful to make targets that depend on multi-user.target now depend on custom-system.target. With just your configuration booting in graphical mode won't activate rc.local. In fact I have made my rc.local script after network.target. Although not exactly what I was asking, it seems to fulfil my need.
Offline
I use the following rc-local.service, and in particular the SysVStartPriority=99 compatibility option:
[Unit]
Description=/etc/rc.local Compatibility
ConditionFileIsExecutable=/usr/local/sbin/rc.local
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/rc.local
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99
[Install]
WantedBy=multi-user.target
See man systemd.service.
I agree that a rc-local replacement is very useful as a scratchbook for system administrators who needs, mostly as an experiment, to start quickly and blindly something as root at boot time. This is definitely not the systemd way of doing things, but systemd is so kind to provide a compatibility option for heretics.Enjoy! :-)
Mortuus in anima, curam gero cutis
Offline
Having a whole new target just for the purpose of running a single script is a little overkill. I will work but you also need to be careful to make targets that depend on multi-user.target now depend on custom-system.target. With just your configuration booting in graphical mode won't activate rc.local.
When I made my earlier suggestion I didn't know that graphical is the default target. That being the case, I think an After=multi-user.target service would be ideally associated with graphical.target.
But whether the Constitution really be one thing, or another, this much is certain - that it has either authorized such a government as we have had, or has been powerless to prevent it. In either case, it is unfit to exist.
-Lysander Spooner
Offline
When I made my earlier suggestion I didn't know that graphical is the default target. That being the case, I think an After=multi-user.target service would be ideally associated with graphical.target.
I am now for practical purpose happy with just starting it after network.target. But my ideal purpose was to launch the script as the last thing of multi-user.target and and made that robust to configuration change. My ideal was that it continue to work if I change the default target. I choose the target I want to boot at the bootmanager prompt by passing a 'systemd.target=' as kernel command line, so that I have an entry to boot in graphic or text mode from syslinux. Moreover, if we make the script part of the graphical.target, I would then want to launch it before the other things in graphical.target.
Last edited by olive (2014-10-16 13:54:21)
Offline
This appears to do the right thing:
# /etc/systemd/system/rc-local.service
[Unit]
Description=Custom rc-local launcher
DefaultDependencies=false
After=multi-user.target
[Service]
Type=forking
ExecStart=/etc/rc-local
[Install]
WantedBy=multi-user.target
From the logs:
Oct 16 09:54:10 fortuna systemd[1]: Starting Multi-User System.
Oct 16 09:54:10 fortuna systemd[1]: Reached target Multi-User System.
Oct 16 09:54:10 fortuna systemd[1]: Starting Custom rc-local launcher...
Oct 16 09:54:10 fortuna systemd[1]: Starting Graphical Interface.
Oct 16 09:54:10 fortuna systemd[1]: Reached target Graphical Interface.
Oct 16 09:54:10 fortuna rc-local[545]: SUCCESS - running rc-local
Oct 16 09:54:10 fortuna systemd[1]: Started Custom rc-local launcher.
Oct 16 09:54:10 fortuna systemd[1]: Startup finished in 1.603s (kernel) + 17.810s (userspace) = 19.413s.
The "DefaultDependencies=false" line breaks the ordering cycle caused by "After=multi-user.target" and "WantedBy=multi-user.target"
*Edit* - changed "Type=oneshot" to "Type=forking" as advised below by amish.
Last edited by branch (2014-10-16 19:31:28)
Offline
TIme stamps of all targets are 09:54:10!!!
Does that mean everything is starting together?
I doubt that system can reach from multi-user target to graphical target in just mili-seconds! (unless there is nothing in ur multi-user target)
Also as I said earlier - oneshot seems to have side effect. If your rc.local script is creating background process, they get killed once the script returns/exit.
PS: I did not try oneshot in newer systemd - but atleast in old systemd background processes were getting killed
Last edited by amish (2014-10-16 17:29:39)
Offline
That was not the full log, just the relevent part. The first line "Starting Multi-User System." is when systemd begins starting the multi-user.target unit, ie. after all of the multi-user.target dependencies have already been satisfied. Since target units don't do anything they are always "Reached" immediatly after they are "Started".
The key point of the log dump is to show that rc-local.service is started after multi-user.target is reached even though we had "WantedBy=multi-user.target" in rc-local.service, which would usually result in the opposite order.
Good catch on "oneshot" killing child processes. I tested with the scripts below, you are right. "Type=forking" works. It even kills the child processes properly when I "systemctl stop rc-local.service". I will edit my above post so the correct working service file is in the thread.
#!/bin/sh
# /etc/rc-local
echo 'SUCCESS - running rc-local'
/root/bin/echod.sh &
#!/bin/sh
# /root/bin/echod.sh
while true; do echo "ECHOD - running"; sleep 5; done
Offline
Pages: 1