Shell Run script on user logon

Hello,

I assume there is a way to run a script each time a user logon to the system? I tried adding my script to /etc/profile.d, but no dice...

Any ideas?

Thanks.
 
My script that is in the profile.d directory is a bash script. My user that is logging in, has its shell set to bash... but nothing happens.
 
/etc/profile.d is a linux-ism; and it is actually ingested/processed via (for example) the /etc/profile script (again, on linux) deciding to look through & source the files in it.

If you want support for a profile.d directory with FreeBSD's bash(1) installed from shells/bash, you'll need to add it to /usr/local/etc/profile.

(Note it's been suggested to add something like this to base FreeBSD, but it is not currently there.)
 
/etc/profile.d ...
(Note it's been suggested to add something like this to base FreeBSD, but it is not currently there.)
It has already landed on October 2022 in 14.0-CURRENT (main), then Merged From Current in stable/13, and 12.4-RELEASE, but not in 13.1-RELEASE. It will be available in 13.2-RELEASE.

bin/sh/profile (/etc/profile)
Code:
...
# System-wide .profile file for sh(1).
...
# Load each .sh file in /etc/profile.d/, then /usr/local/etc/profile,
# then each .sh file in /usr/local/etc/profile.d/.
...

fumanchu, your system seems to missing the updated /etc/profile file. Just copy the file, replace with it the one on your system and put your script under which profile.d directory you see fit.
 
If you don't mind having separate scripts for each individual user, modify ~/.bashrc for bash() shells (or ~./shrc for sh() shells, where:

~ is shorthand for the user's HOME directory.
 
I am running 12.4. The /etc/profile files looks correct. I must have something incorrect in my set up causing it not to run correctly... I will need to do some more digging on Monday.

Thanks for all the feedback.
 
Let's go back and ask a few basic questions. You said "each time a user logon". Do you many each time a specific user logs in? For example, do it for user Bob, but not for Adam or Charlie? Or do you many each time any user logs in, independent of their user name? Do you want to do that for all users that exist today, or for all present and future users? Does that include root?

Next question: What does "logon" even mean in this context? Do you need to differentiate between console login (perhaps using a GUI, such as DE or XWindows login) and login over the network? Does it need to be run again when a user logs in multiple times, or should it deliberately not be run if the same user has multiple logins?

Do you care whether the user is set up for tcsh versus sh? How about additional shells such as zsh and bash?

And what should happen if a new shell is started, without a new login?

Once we know these requirements, it becomes easier to design a solution from a combination of files such as /etc/profile and /usr/local/etc/profile, ~/.profile, and ~/.bashrc and other shell-specific setups.
 
Alain De Vos, the default shell is 'sh'.
ralphbsz, those are all good questions.

My FreeBSD saga has been going on for quite some time now. I am in the process of creating custom FreeBSD memstick image. This image has a bunch of prefigures setting, helpful setup scripts, and a bunch of 3rd packages, built into the image so that no internet connection is needed. I have that image created.

What I would like to do, is have my /usr/local/bin/initialize.sh script run automatically when either 'root' or my preconfigured 'support' user, logs in for the 1st time. I actually got this to work by:
  1. Adding /bin/sh /usr/local/bin/initialize.sh to root's .cshrc file.
  2. Adding sudo /bin/sh /usr/local/bin/initialize.sh to support user's .cshrc file.
  3. Creating an /initialize file, which the /usr/local/bin/initialize.sh checks for. If /initialize is found, the script runs and then /initialize is deleted. If the file is not found, the script does not run.
Is there a better way of doing this?
 
That sounds reasonable. If you want to run it ONCE after installation, you need to store state somewhere, to remember whether it got run or not. The file system is pretty much the only place you can store state. We could now argue whether the location /initialize is the best location for it; personally would look at the file system hierarchy for FreeBSD (see "man hier" or "man 7 hier") and then put the file in /usr/local/etc, but that's a small difference.

Minor simplifications (all of those are suggestions, and depend on personal style): Instead of calling it initialize.sh, just call it initialize. It's obvious that it is a shells script, from looking at the first line, don't need to repeat that fact. And then don't call it initialize (which is very ambigous), but "fumanchu_initializate" or "after_install_initialize" or something similarly descriptive. Since it is not a program that normal users use for productive work, but it's part of system administration, /usr/local/sbin might be a better location. To call it, you don't need to do "/bin/sh /usr/local/bin/initialize.sh", but you can put /bin/sh into the first line of the script itself (as a shebang line: "#!/bin/sh"), mark it as executable with "chmod a+x /usr/local/bin/initialize.sh", and call it directly from the .cshrc as "/usr/local/bin/initialize.sh" (without the /bin/sh in front), similar with the sudo line.

And one nasty question: So this initialize.sh script runs, and deletes the /initialize file. But what order do these operations happen in? For example, say that the first thing the initialize.sh script does it so delete the /initialize file, and then do its work. But what if the script crashes? It doesn't have to be it's own fault (a bug), it could be that power got turned off right in the middle of the script. From this bug, we learn that deleting /initialize has to be the last thing the script does, great. But now what happens when the script crashes halfway through? Sure, it will get restarted a second time, but the first half of its operations have already been done. So when you write that script, you need to think through it this way: It is a series of steps, each of which has to be atomic and idempotent. Atomic means the step either gets completely done or not at all, and there is no "halfway". Idempotent means it's OK to do the same step again even if it already got done, it won't do any harm. This is a specific example of what database people call "ACID" properties: Atomic, Consistent, Isolated, and Durable, with Idempotence being a good way to accomplish those in a transaction system.
 
The /initialize is only removed if the script is successful. I did moved the file to /var/tmp/initialize.
 
Back
Top