Forum > Unix

File path to ${HOME}

<< < (2/2)

colo:
Sorry for raising this maybe slightly off-topic remark, but since I've seen something along the lines of


--- Code: ---GetEnvironmentVariable('HOME')

--- End code ---

to determine a user's home directory on GNU/Linux and other UNIX-like OSes quite often, I would like to remind everyone that it's not a given this environment variable exists or is set to the proper value. Most interactive shell sessions will have it set, but not all commonly encountered (and even less so, all possible) execution environments will have it. Even getuserdir seems to get it wrong, at least per its docs, and if you call it with an empty HOME value in the env, it will return "/tmp", which is its own can of worms entirely.

Only getpwnam(3) or getpwuid(3) from the host's C library will always yield the right thing (even in the face of more exotic circumstances, like the user database not living in /etc/passwd due to nsswitch, for example), which is what you should call from any fpc code to get this right. Unfortunately, it escapes me how to do that, since the only reference I could find is to the deprecated libc stuff in https://www.freepascal.org/daily/packages/libc/index-8.html#SECTIONG - but if anyone else can chime in, I'd be eager to learn! :)

marcov:
Maybe the "users" unit as mentioned in the libc article as alternative ?

https://wiki.freepascal.org/libc_unit

colo:
Yes! Excellent, this led me to the right thing :) The procedures buried in the related `pwd` module call `getpwnam` and friends, as it should be.

For demonstration purposes (I'm on GNU/Linux here, with a boring passwd/shadow-based NSS user and group database), consider this program:

--- Code: ---program userhomedir(output);
uses sysutils, baseunix, pwd;
var
    pwrec: PPasswd;
begin
 { Sometimes wrong, don't use }
 writeLn('GetUserDir: ' + GetUserDir);

 { Correct way to determine the current user's home directory }
 pwrec := fpgetpwuid(FpGetUid);
 writeLn('FpGetPwUid: ' + pwrec^.pw_dir );
end.

--- End code ---

The struct that contains pw_dir also carries other useful per-account data, as documented here.


Demo shell session output:

--- Code: ---$ fpc userhomedir.pas
Free Pascal Compiler version 3.2.2 [2023/05/07] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling userhomedir.pas
Linking userhomedir
12 lines compiled, 0.1 sec

# "happy" path
$ ./userhomedir
GetUserDir: /home/colo/
FpGetPwUid: /home/colo

# where GetUserDir gets it wrong
$ HOME= ./userhomedir
GetUserDir: /tmp/
FpGetPwUid: /home/colo

--- End code ---


A soon as a program that uses GetUserDir ends up being run as a system service, chances are its notion of home will be off. So I would encourage anyone to use the `pwd` module instead, and if the value of HOME is to be accounted for, maybe handle this in custom code.

Raskaton:
Maybe just use:
ExpandFileName https://lazarus-ccr.sourceforge.io/docs/rtl/sysutils/expandfilename.html

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---uses SysUtils; ExpandFileName('.');  //app directoryExpandFileName('~/');  //home absolute path like: /home/username/  or /root/ExpandFileName('~/.local/');  // /home/username/.localExpandFileName('~/..');  // /home/ or  / Never use it by myself  ;)

Upd. Test it in Linux (KDE)

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  writeln('ExpandFileName(''.'') = ', ExpandFileName('.'));  writeln('ExpandFileName(''~/'') = ', ExpandFileName('~/'));  writeln('ExpandFileName(''~/.local/'') = ', ExpandFileName('~/.local/'));  writeln('ExpandFileName(''~/..'') = ', ExpandFileName('~/..')); 
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---ExpandFileName('.') = /home/raskaton/Projects/Lazarus-Projects/TestConsoleAppExpandFileName('~/') = /home/raskaton/ExpandFileName('~/.local/') = /home/raskaton/.local/ExpandFileName('~/..') = /home wrong slashes also converted

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---ExpandFileName('~\..') = /homeExpandFileName('~\..\') = /home/ 

Navigation

[0] Message Index

[*] Previous page

Go to full version