Environment Variables Behavior On Haiku

This is not a bug, but a feature.

2 Likes

This deserves a little more details

BeOS decided (long before the XDG specification existed) to provide the location of standard folders using a C and C++ API (the function is called find_directory). The idea in either case is the same: the OS knows where these files should be located, and the applications should not hardcode a path on their own.

For simplicity when porting applications we now have also implemented the XDG way. However, this implementation is done only in the environment set by bash. And when running applications from Tracker, there is no bash anywhere in the parent processes, so that environment simply isn’t there.

The solution would be to move the setting of these variables to the launch daemon (who should be in charge of these things in Haiku). But for some reason, it seems Haiku users and developers instead decided to accept the fact that environment variables are inconsistent between Terminal and running apps from Tracker, and prefer to patch thousands of apps to workaround it instead of actually fixing the problem.

If you think this should change, please at least upvote the related tickets to attract the attention of Haiku developers:

https://dev.haiku-os.org/ticket/12534
https://dev.haiku-os.org/ticket/7682

(the upvote button is at the top right, just below the menu in Trac. You need a Trac account to vote)

7 Likes

So these patches are a workaround?
There is no find_directory used?!
How to use this find_directory correct then?

Only searched for them and linked them here, haven’t fiddled with XDG_DATA_HOME myself, or didn’t have any luck with them :slight_smile:

Has there been a lot of discussion around this? I have not always kept up but I feel like there has not been a lot of discussion. Your wording makes it sound like people have made proposals and been rejected repeatedly but I think this is just a case of no one really working on it.

Is the solution as simple as launch_daemon reading in the environment and making sure that everything it launches just gets that same environment? Will there be a GUI to manage these environment variables like in Windows? What happens if one of these is changed, can that be propagated live in a running system, or would it require a reboot? I feel like there is a known “user mental model” for this with Terminal and bash, but it becomes less clear with moving these to launch_daemon.

I read those bugs and it does seem indeed there are issues with both native and non-native apps, though as expected it affects non-native apps more.

I find environment variables very clunky and they remind me of all the things I dislike about Linux, but if the inconsistency affects many apps I certainly could be convinced that this should be fixed, and launch_daemon might even make it so that it is fairly clean. Though I honestly don’t know the answers to some questions above, and I think for many developers the launch_daemon is a bit of a mystery, which is why I think maybe this issue needs some broader discussion.

1 Like

The simple solution is to have launch_daemon set some default environment variables. They could be hardcoded to fixed values for a start, and it would already fix most of the problems. The terminal/bash profile can still override them as needed.

This is how it works in other UNIX OS as well. For example on Linux, systemd (as the init process) is responsible for initiaizing the environment, and then the bash profile can add things to it (or even remove things) for programs that are run inside a shell session.

In fact, a quick look at the launch daemon sourcecode will show you that this is already done. The method used is LaunchDaemon::_SetupEnvironment() and there does not seem to be any mistery involved here. It just calls the UNIX setenv function. Additionally in _StartSession it also sets the HOME variable.

So it’s just a matter of adding some more setenv calls in these two places, and removing the corresponding entries from the bash profile. A very simple fix.

What I don’t understand is how a lot of effort can be put into patching many applications to workaround the problem, when the proper fix would take a lot less effort. The same thing happened for the lack of a features.h header file, where people apparently were happy adding -D_BSD_SOURCE to compile flags of thousands of apps, instead of just adding the define in features.h where it should have been from the start. It results in lots of frustration for haikuports maintainers (having to keep these patches working), for 3rd party applications developers (wondering why Haiku behaves differently from all other systems for no reason), and for us Haiku developers (because no one bothers to report the problem up to us, or push us to fix it).

7 Likes

For what it is worth you have convinced me this change is good to improve environment variable handling. I can look into making this fix once I get a Haiku dev environment going again, which should be fairly soon.

As for the header issue, I think what you say also makes sense, and if there are simple things we can do to improve porting some libraries or applications we should do that. I would strongly suspect there is not any active effort to make porting harder by resisting these changes, more like no one has bothered to make them and most people working at HaikuPorts either don’t want to change Haiku or they don’t feel empowered to. This is more of a cultural problem than a technical one. Maybe we need to make sure the community knows that Haiku is open to changes that make porting easier as long as they don’t greatly detriment “the Haiku way” as we can determine that.

8 Likes

Maybe a nice tutorial for developer/porter would be helpful here!

Maybe applications could opt into this with a specific flag in their resource file? That way by default no extra environment variables would be set, and native Haiku apps should not need them. But for ported applications this flag could be set.

Maybe clipboard like Amiga’s ENV. A device where local values are storred. All in special prepered ram disk.

Apologies for trying to climb on here when the train has probably already left long ago, but I just ran across the origin of this thread and understanding the question better … not that anyone cares, but I don’t think I’m really such a fan of adding the XPG stuff, just seems rather foreign.

But that doesn’t mean anyone has to add porting hacks for Haiku.

Suppose there’s an environment wrapper, designed for applications that need a certain set of environment variables, like this XPG stuff for example. It sets those variables as appropriate and execs the application. These wrappers could be stacked, to accommodate any conceivable configuration of environment extras. I believe Python applications already use wrappers like this, for the sake of an icon.

I have begun looking into this a bit, but have not had a chance to work on the code yet.

The current status quo really is not good because of the difference in behavior in environment variables when applications are run from Terminal versus when they are run from anywhere else (Tracker, Deskbar, Launchbox, etc.) It isn’t necessarily even a “ported apps or not ported apps” situation, Pe for example had a bug related to this because apparently Haiku did not provide environment variables in the same way as BeOS.

I believe this is because of the move to the launch_daemon. Previously (and on BeOS) there was a Bootscript which set up a lot of these, but now only a few are set up by launch_daemon and the rest are only set up by the shell when Terminal is run. My plan is to just have the launch_daemon run a sub-shell to get the environment variables and then fill all those in for various base applications and then they will get properly set up in subsequent children applications.

I want to use the sub-shell because that still allows for easier customization by users in their personal shell files. I think it will work but I will need to test. It will involve parsing the output of the env command but I don’t think that is too bad.

sh seems like a heavy dep to run during boot just for some env variables, is that really needed?

It’s fine, if it works. There are some reasons why you might not want a shell in there, but economy isn’t one of them - unless you’re trying to fit everything on a chip or something like that, the resources added by a UNIX shell interpreter are inconsequential.

Do you feel like the Terminal starts too slow? Right now it just runs the same scripts I am talking about. If you are not talking speed but sh being a “dependency” to launch_daemon, well it is already in the OS and used by Terminal so I think should be fine.

So I doubt it will have any obvious consequence but I can time it to be sure. I plan to write a small tool to try to do it outside launch_daemon first. The alternative is having to rewrite our SetupEnvironment shell scripts in C++, which probably isn’t too terrible, except it then becomes hard-coded in launch_daemon and user customization is also much more difficult. It feels like having launch_daemon run those scripts is the least bad option. Then of course the shell profile will no longer need to run them so Terminal sessions will load faster. I think paying the price once on boot is better. Either way I bet we are talking milliseconds unless someone does something stupid in the shell scripts.

Also in theory since all programs will now have this larger environment, forking and execing programs might be slightly slower (though maybe not depending on how the environment block is handled.) The only alternative is the current situation with different environment between Terminal and everything else, which I think most people think is not a good situation.

1 Like

Yes I do, but that is partially because of the way the profile works now, perceptibly it becomes much better with mksh instead of bash and some stuff removed from the profile. But that is a bit beside the point.
sh is a complete language interpreter you would start during boot which seems extremely overkill for assigning variables to the ouput of c++ calls, which also gives you additional redirections to do it that way.
Add to that that sh is terrible to programm in with its pitfalls and i’m not really convinced it is worth the effort.

I don’t think we need to have env variables for user programms more than absolutely neccesry, allowing user costumization directly here also leads to unpredictability for programms that actually make use of them.
Especially for packagers who might not expect vars users put there.
just my 2 cents though.

Forking for programm with tonier or bigger env on unices atleast doesnt have a linear speed impact, but rather a random one from what i remember. Though this could be different here.( I don’t think we should fork() in any case though )

edit: For terminal sessions it probably doesnt matter much where you assign vars, you need to start the shell in any case.

Terminal isn’t really invoking any extra shells, that I can see. It does of course run a shell, but since that’s more or less its purpose I would discount that as a cost. That shell interprets the environment setup profile files itself, on startup, and I don’t see anything in there that invokes another shell (script.)

There are a number of executables, though - e.g., finddir runs repeatedly to get the XDG parameters. That might be avoidable for a C++ program that’s part of the Haiku source tree.

Considering “stupid” is available in infinite quantities, I would not under estimate those someones…

Does the proposed change mean a poorly configured shell environment could prevent Haiku from booting?

As a test in Haiku, I modified the config/settings/profile to cause a hang when setting a variable. And as expected, opening a Terminal caused it to seem to be hung. Hitting Ctrl-C (a few times) eventually made the prompt appear and all was good. With the proposed approach, I don’t think a Ctrl-C will be available to get Haiku unstuck during boot or a restarting daemon that will just reread the same bad settings.

And thanks for sharing your ideas on possible solutions for Environment Variables Behavior On Haiku. It’s interesting learning how Haiku works and I wish you the best on whatever approach you take.

Hi Zakero,

It turns out launch_daemon already calls the shell to load variables from the Haiku SetupEnvironment shell script, so my idea was not too crazy and in fact is already done. Unfortunately many of us discussing this earlier were not aware of this until recently. I should have done more research before discussing this too much, which is why I have not responded more before your post. I will say in all our defense the various components for this are kind of spread around so it is not obvious what is happening.

The “bug” is simply that some things (like USER, GROUP and various XDG_ prefixed variables) are only created by the profile script which is run by the Terminal and the “quick fix” is indeed to move these to the previously mentioned SetupEnvironment.

But with all that explained, I do think it might make sense to move some of these into the C++ code of launch_daemon as they are unlikely to need to be changed. Using the shell script provides more flexibility and we probably will want to continue to have that so user’s can add their own variables (to $HOME/config/settings/boot/UserSetupEnvironment, see line 51 of the SetupEnvironment script), but it might speed up the boot a bit to do less in the shell script.

To directly address your concern, yes, someone could probably make their boot process be delayed with a bad shell script. I suspect the launch_daemon won’t completely hang though, it forks itself to load the shell script. It might be worth testing this if you want to add your hanging code to that UserSetupEnvironment file I referenced above. I don’t think it will break the boot but it might be good to see what happens. If this totally messes up our Haiku system, don’t worry, there is a safe mode which does not load this file.

1 Like

Thanks for the info. I modified the UserSetupEnvironment script to hang and Haiku did become unresponsive.

I am running Nightly hrev54979 x86_64 in QEMU emulator version 5.2.0 (openSUSE Tumbleweed) with “-smp cpus=4” and “-m 4G”. When booting with the bad script, Haiku will boot to the blue desktop screen with the “hand” cursor then hangs. Nothing else appears until after a period of time, a dialog window pops up saying the was an error with the application ‘/bin/sh -c . “/system/boot/SetupEnvironment”; export -p’, the options “Terminate”, “Debug”, “Save report”, “Write core file” and a “Oh no!” button. At this point the keyboard and mouse are unresponsive. I don’t know if the lack of input controls is because of QEMU or Haiku itself. Also, I am unable to test with other VMs or on real hardware.

shot-2021-03-11_11-04-47