Make a login/logout script in mac

105 views Asked by At

I have a shell script which I want to run at login as well as logout.

It's something like this

#!/bin/bash

# Define the log file path
LOG_FILE="/Users/kamabokogonpachiro/Desktop/logfile.log"

# Function to log login
log_login() {
    echo "$(date) - User $1 logged in" >> "$LOG_FILE"
}

# Function to log logout
log_logout() {
    echo "$(date) - User $1 logged out" >> "$LOG_FILE"
}

# Check if the script is called with a username argument
if [ "$1" ]; then
    # If the script is called with "logout" as the first argument, log the logout
    if [ "$1" = "logout" ]; then
        log_logout "$2"
    else
        # Otherwise, log the login
        log_login "$1"
    fi
fi

The login script is saved at ~/Library/LaunchAgents/com.user.login.plist and the contents are

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.login.sh</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/kamabokogonpachiro/Desktop/logfile.sh</string>
        <string>login</string>
        <string>$(whoami)</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>WorkingDirectory</key>
    <string>/Users/kamabokogonpachiro/Desktop</string>
</dict>
</plist>

Similarly the logout script is located at ~/Library/LogoutAgents/com.user.logout.plist and the contents are

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.logout</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/kamabokogonpachiro/Desktop/logfile.sh</string>
        <string>logout</string>
        <string>username</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

I did launchctl load ... as well.

Still, they are not working the shell script is marked as executable as well. I don't know what am I missing. Is my approach incorrect? Are there any better ways? I tried with last but the BSD one is different from the Linux (GNU) one and not that versatile.

1

There are 1 answers

1
tripleee On

I don't think you can use shell facilities like a command substitution $(whoami) in the .plist file; it will simply be passed in as a literal string, as if you had written single quotes around it in the shell.

Just refactor your script to run whoami if the first argument is login; or perhaps simply use $USER which will already be set by the system.

You also seem to have forgotten to include the Program key in your .plist files. I don't know if Bash cares, but I'd add it just in case.

Tangentially, it's weird to do these things in the user's Desktop directory. Probably create a hidden file in the user's home directory instead; the user can create a symlink to it on their desktop if they like. I have similarly changed the location of the binary to be in your bin below.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.login.sh</string>
    <key>Program</key>
        <string>/bin/bash</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/kamabokogonpachiro/bin/logfile.sh</string>
        <string>login</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>WorkingDirectory</key>
    <string>/Users/kamabokogonpachiro</string>
</dict>
</plist>

See also https://apple.stackexchange.com/questions/110644/getting-launchd-to-read-program-arguments-correctly

Also, don't use upper case for your private variables.

#!/bin/bash

# Define the log file path
logfile="~/.logfile.log"

log_login() {
    echo "$(date) - User $USER logged in" >> "$logfile"
}

log_logout() {
    echo "$(date) - User $USER logged out" >> "$logfile"
}

case $1 in
    login) log_login;;
    logout) log_logout;;
esac