You are not logged in.

#1 2014-10-09 19:36:30

olive
Member
From: Belgium
Registered: 2008-06-22
Posts: 1,490

emulating rc.local

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

#2 2014-10-09 19:51:48

alphaniner
Member
From: Ancapistan
Registered: 2010-07-12
Posts: 2,810

Re: emulating rc.local

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

#3 2014-10-09 20:24:57

olive
Member
From: Belgium
Registered: 2008-06-22
Posts: 1,490

Re: emulating rc.local

alphaniner wrote:

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

#4 2014-10-09 20:48:04

alphaniner
Member
From: Ancapistan
Registered: 2010-07-12
Posts: 2,810

Re: emulating rc.local

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 wink ) 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

#5 2014-10-09 21:14:17

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,534
Website

Re: emulating rc.local

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

#6 2014-10-09 22:31:42

olive
Member
From: Belgium
Registered: 2008-06-22
Posts: 1,490

Re: emulating rc.local

Trilby wrote:

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

#7 2014-10-09 23:34:31

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,534
Website

Re: emulating rc.local

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

#8 2014-10-10 01:54:54

amish
Member
Registered: 2014-05-10
Posts: 470

Re: emulating rc.local

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

#9 2014-10-10 07:02:46

olive
Member
From: Belgium
Registered: 2008-06-22
Posts: 1,490

Re: emulating rc.local

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

#10 2014-10-10 07:41:09

amish
Member
Registered: 2014-05-10
Posts: 470

Re: emulating rc.local

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

#11 2014-10-10 13:22:20

ANOKNUSA
Member
Registered: 2010-10-22
Posts: 2,141

Re: emulating rc.local

Trilby wrote:

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.

olive wrote:

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

#12 2014-10-12 03:17:57

Pse
Member
Registered: 2008-03-15
Posts: 413

Re: emulating rc.local

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

#13 2014-10-12 03:23:29

amish
Member
Registered: 2014-05-10
Posts: 470

Re: emulating rc.local

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

#14 2014-10-12 09:14:49

Raynman
Member
Registered: 2011-10-22
Posts: 1,539

Re: emulating rc.local

amish wrote:

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.

amish wrote:

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

#15 2014-10-12 11:12:05

amish
Member
Registered: 2014-05-10
Posts: 470

Re: emulating rc.local

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

#16 2014-10-12 22:29:11

Raynman
Member
Registered: 2011-10-22
Posts: 1,539

Re: emulating rc.local

Yes then the forking makes sense. As for the ordering, it still sounds like you're only "supposing" it will not work.

Offline

#17 2014-10-15 23:08:35

branch
Member
Registered: 2014-03-16
Posts: 209

Re: emulating rc.local

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

#18 2014-10-16 06:51:21

olive
Member
From: Belgium
Registered: 2008-06-22
Posts: 1,490

Re: emulating rc.local

@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

#19 2014-10-16 08:00:24

patroclo7
Member
From: Bassano del Grappa, ITALY
Registered: 2006-01-11
Posts: 915

Re: emulating rc.local

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

#20 2014-10-16 13:19:48

alphaniner
Member
From: Ancapistan
Registered: 2010-07-12
Posts: 2,810

Re: emulating rc.local

olive wrote:

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

#21 2014-10-16 13:51:59

olive
Member
From: Belgium
Registered: 2008-06-22
Posts: 1,490

Re: emulating rc.local

alphaniner wrote:

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

#22 2014-10-16 15:04:13

branch
Member
Registered: 2014-03-16
Posts: 209

Re: emulating rc.local

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

#23 2014-10-16 17:29:08

amish
Member
Registered: 2014-05-10
Posts: 470

Re: emulating rc.local

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

#24 2014-10-16 19:28:55

branch
Member
Registered: 2014-03-16
Posts: 209

Re: emulating rc.local

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

Board footer

Powered by FluxBB