How do i get the user name in a Makefile? - linux

I'm making a simple game for Ubuntu and to update the highscore list, it needs a single file at runtime, called 'highscores.bin'.
I wish to put this file at
/home/(USER)/.game_name
I've researched a little and found that from inside a Makefile i can get the environment variable $USER.
So in the Makefile, at the 'install' target, i've added:
mkdir -p $(DESTDIR)home/$$USER/.game_name
But when i run 'sudo make install', the Makefile installs it as:
/home/root/.game_name
How can i get the (non-root) user name in a Makefile?
P.S.: I'm writing the Makefile by hand. No ./configure
P.S.2: I dont want to do
mkdir -p ~/.game_name
because i want to be able to change DESTDIR if i want to install to a temporary directory.

Well, if you want that file during runtime I would recommend that you create it during runtime. The Makefile is considered only during compile time. This is obviously a problem if the program is compiled and then executed by different users, some of which may not even exist at compile time.
During runtime you can get the home directory as shown here (if you are using C/C++). Then you can check for existance of the highscore folder/file and create it if you need to. If you want a highscore file for all users, you should put it in the home directory of a special user, but rather somewhere else in the file system. This is for example done by the game xjump.
And about your Makefile, the $USER variable is translated to root because of the sudo command on
sudo make install
The user actually running make is the superuser: root.

You want to install your program for every users? So it's better if you create the /home/user/.game_name directory when the user run the game, not when root installs it. Otherwise, only the user who call sudo make install will have it's highscore list. If you have only one user, do not install it system-wide, but in the user directory.
I suggest to initialize users files at game first run. So every users, even users that didn't exist when the game was installed, can have their highscore list. You can add the initializing code into your game (c++, java or anything else) or just call an external script that does it (not so elegant). Avoid to create user-related files at installation time.

Related

Dynamically get username in Postinst script of .deb package

I wrote Postinst script for changing owner and file permission:
chown -R $(whoami) ~/Desktop/my_file.desktop
chmod 777 ~/Desktop/my_file.desktop
but after installation it does nothing.
I'm really not getting what part of script is wrong. Please tell how to get dynamically username in Postinst script?
Package installation runs as root, unconditionally. There is no concept of an invoking user; indeed, the package installation may happen e.g. before any user accounts exist on the box.
It's extremely unclear what you actually hope to achieve, but it looks like perhaps your package should simply install a script which then performs the task when the user runs it. This will also conveniently create a file which is already owned by the current user, without any chown trickery.
Even if a user exists, there is no guarantee that they have a Desktop directory in their home directory, or that they are currently, or ever, logged in using a GUI.
Finally, whatever you are attempting to do, chmod 777 is wrong and dangerous. You should absolutely not assign write access for everyone, to anything, ever.
(Okay, so there are two or three obscure scenarios related to system administration where this is actually required and useful; otherwise it should probably be technically impossible in the first place.)

Can't execute from /usr/local/bin/ symlink

I've recently had to compile a program (Riak) from source since they don't have a repo available for Ubuntu 16.04 yet.
I've compiled the program and copied it to /opt/riak where it works fine.
Since this program requires sudo privileges, I've decided to symlink /opt/riak/bin/riak to /usr/local/bin/riak instead of adding the variable to the path via a profile.d file (because in order to work with sudo I'd have to remove env_reset from /etc/sudoers which I rather not do).
The error I get is the following:
/usr/local/bin/riak: 8: .: Can't open /usr/local/bin/../lib/env.sh
Shouldn't the symlink execute the file from the original's working directory? Is there a way to make it work?
The error message is almost self explanatory. Apparently the riak executable is trying to find a file called env.sh using a path relative to its own, namely ../lib/env.sh. Originally, this would resolve to the following path: /opt/riak/bin/../lib/env.sh, which is the same as /opt/riak/lib/env.sh. But now is trying to find the file at /usr/local/bin/../lib/env.sh which is the same as /usr/local/lib/env.sh and obviously the file is not there.
You have the following options (in order of preference):
Leave the program in /opt and invoke it from there
Leave the program in /opt and create a small wrapper shell script in /usr/local/bin that calls the original executable (see at the end of this post).
Recompile the program passing the right parameters to its configure script (e.g. --prefix=/usr/local) so that it works from /usr/local.
I would recommend against option 3; I prefer to let the /usr directory be managed by the distos package manager. If I have to compile something myself, I prefer to put it in a dedicated directory bellow /opt. This way, if I want to remove it later on, I can just delete that directory.
Example wrapper script for option 2:
#!/bin/bash
exec /opt/riak/bin/riak "$#"

Debian Package Creation postinst as non-root

I have created quite a few deb files, i have no problems doing that and they all run beautifully. However, if i want to replace a file in users home directory I am unsure on how to do that.
I have tried making a postinst to rsync the files from a predefined location to home directory, but since the postinst file is being run as root ( due to the debian installer running as root ) it is being sent to the root home directory and not the user's home directory....
Here's an example of the deb file contents :
Debian Directory ---> Control File ----> Postint File
usr/share/desktop (directory with files inside)
The postinst file has the sync command to send those files to users home:
#!/bin/sh
rsync -av /usr/share/desktop/ ~/.config/desktop/
The problem is it is sending the files to Root/home... not the default users home :(
I don't have the username of the user since this will be used on many computers with different users, therefore I can't use sudo -u username.
So what do I do? how do i replace files in users home directory from deb install? Any help is much appreciated.
In a Bash script, ~ refers to the current user's home directory. The package installation scripts are always run as root, so that's what "current user" means in this context.
(You could argue that the package installation is probably initiated by a user running su or sudo, but in the general case, you cannot assume this to be the case.)
Modifying user files from a system package appears extremely suspicious in any event. If the need is genuine, this should probably not be approached as a system package installation question in the first place. What are you actually trying to accomplish?
Not only are you violating the basic principle that package management should not meddle with user files; a consequence of this arrangement is that the operation can only be performed once: If the user has installed the package, attempting to install it again does nothing (at least until you uninstall).
A more manageable and predictable approach would seem to be making the package provide this functionality, but leave it to the user to invoke the actual sync (overwriting) script as needed. Perhaps you want to hook it into the desktop startup scripts somehow.
Having said that, sudo exposes the invoking user's identity in $SUDO_USER so you could look for that, and simply fail if it is not set.
As an aside, package scripts should work with dash so you need to avoid bashisms - prefer $HOME over ~, for example.
I managed to find a workaround, although it is not exactly what I was looking for, but here is my solution, at least for now.
#!/bin/sh
#This will move the desktop settings to required folder.
szAnswer=$(zenity --entry --text "Enter your login username\nThis must be entered correctly\n" --entry-text "Enter name of profile to use:")
xfce4-terminal -e "sudo rsync -av /usr/share/Desktop/ /home/$szAnswer/.config/xfce4/"
exit 0
In other words, the user gets asked to enter his username, and the files get copied to that user's home directory. The advantage is that if he does have multiple users, it will use the correct user. The disadvantage is if he enters username wrong, even a spelling mistake, the install will fail.
But it does work, I have tested. If anyone has a better solution I eagerly await your suggestions.

multiple binaries with same name in ubuntu/linux

I have recently installed a webframework play (http://www.playframework.com/) and want to have the play executable in the system path ie $PATH. But ubuntu already defines a command called play. How do I overwrite the system defined command with my framework binary path so that command play on commandline calls my framework rather than the old application.
Installation: I downloaded zipped file of the framework and upzipped in one of my personal folder which contains the docs and the executable.
Never alter the contents of installed packages. Such changes can provoke hard to find problems in the system and anyway, they will most likely be overwritten again in subsequent updates. There are other alternatives:
obviously you can chose another name for your executable
place the executable in another part of your $PATH if its a "personal installation", typically ~/bin is used for such approach. Remember that the order of entries in the $PATH variable is important, first come first serve.
use the traditional /usr/local/bin location for locally added "wild" installations, this way there is some form of clean separation between clean packages and wild installed files inside the system
store your software in some other location and prepend that to your personal or system wide $PATH variable
store your executable under another name and create an alias (see man alias for an explanation) for it which allows to call it by some name that "hides" the original command this way. For this the executable can be addressed with an absolute path, so it dies not have to be found inside the $PATH variable.
In my personal opinion options 2. and 5. and the best if it comes to "personal installations".
If you are sure you'll never use the original play command, you could just remove the binary. But in general, this isn't a good idea, since some system component you don't think of might need it, and the next update will probably restore it.
The best thing to do is to prepend the directory of your play command to the PATH, for example, using PATH=/opt/framework/bin:$PATH in your .profile (assuming your play command installs to /opt/framework/bin/play), or the script that starts your web server, or wherever you need your play command.
Remember that does not make your play command global. A common mistake is to add the path in their .profile file, then call the program from crontab - crontab scripts will not execute .profile or .bashrc.

Bash scripting and user home from root account (Linux)

I'm writing an install script in bash for an application on Linux.
This script copies some files into /usr/bin and /usr/share, so it needs to be executed by a root user, furthermore it makes an hidden directory in the $HOME dir for configuration files.
Here is the problem: if a normal user wants to install the program, he needs to be root. But if he is root, the $HOME directory will be /root/ instead of /home/username.
...and, further, if UserA installs the software, but UserB runs it, UserB won't have the hidden directory under /home/UserB. Also, the hidden directory under /home/UserA will be owned by root, not userA.
So, you need to have the application create the hidden directory, not the installer.
Another possible option is not to install in the system directories; one possible alternative location is /usr/local. However, even that can require root privileges. Think about whether it can be installed in other places, and how it could locate its materials.
However, requiring root privileges to install is not the end of the world - a nuisance for some, but not completely out of order. But requiring everyone who uses to have root privileges is way out of order - and if everyone who uses it needs to run the installer, that is bad.
Final point (for now): if you use sudo, it does not change the value of $HOME, even as you acquire root privileges. However, requiring everyone who uses your application to have sudo privileges is not a good thing either.
Must you use $HOME? Maybe you could prompt for the username and install to ~$username instead?

Resources