LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-21-2004, 04:35 PM   #1
mvt
LQ Newbie
 
Registered: Apr 2004
Location: Lake City, Florida, USA
Distribution: Red Hat and SuSE
Posts: 9

Rep: Reputation: 0
setenv within a program doesn't last


I wrote a C++ program which calls setenv() to change
the "path" environment variable. Within the program
I can then call getenv("PATH") and see the new
value.

But after the program exits, if I list the environment
variables using the tcsh command: setenv | grep -i path
I see the old path, not the one newly set.

Apparently the program is run with a copy of the
environment, which is modified and then discarded.

Any ideas how to make this program work?
I want the path changed within the shell after the
program terminates.

Note: I am using the setenv() command described in
section 3 of the man pages (man 3 setenv).
I also tried system("setenv path=(/bin /sbin)");
but it failed the same way.

Thanks,
Mark

Red Hat Linux version 9
gcc compiler
tcsh shell used
 
Old 04-21-2004, 04:55 PM   #2
jim mcnamara
Member
 
Registered: May 2002
Posts: 964

Rep: Reputation: 36
When you run a program, it runs in it's own separate sub-process.
When the sub-process exits, then all of the environment variables exit with it.

You return to the parent process, which never saw those changes.

If you want to set envrionment variables that stick around, you probably want to try using a simple script -- then execute the script with dot notation like this:
Code:
.  myscript.shl
 
Old 04-21-2004, 05:24 PM   #3
kebabhead
LQ Newbie
 
Registered: Apr 2004
Location: west coast USA
Distribution: redhat 9, fedora core 2, Gentoo
Posts: 20

Rep: Reputation: 0
Hi, I think what you are trying to do willl not work (if I'm wrong I'd love to know the answer!). Since your program is creating a child process which is then used to create the variable using setenv, then when this process exits the enviroment change is lost, it's said much better here:
"A script can export variables only to child processes, that is, only to commands or processes which that particular script initiates. A script invoked from the command line cannot export variables back to the command line environment. Child processes cannot export variables back to the parent processes that spawned them."
Advanced Bash Cripting Guide Ch 4.4

Cheers
 
Old 04-21-2004, 05:26 PM   #4
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Quote:
Apparently the program is run with a copy of the
environment, which is modified and then discarded.
Yes, that is exactly what happens. Only the program itself and its child processes (if the env. var. is exported) have the changed or added env. var. available.

What you could do to fix it is, instead of exiting your program, replacing it with a new shell process. For example: (C..., not C++. Sorry) :
Code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
	char *shell;
	
	/* Get the path of the current shell to start it later */
	shell = getenv("SHELL");
	if (shell == NULL) {
		fprintf(stderr, "Error eding SHELL env. var.\n");
		return 1;
	}		
	
	/* Overwrite env. var. PATH */
	if (setenv("PATH", "/usr/bin", 1) < 0) {
		fprintf(stderr, "Error setting env. var.\n");
		return 1;
	}
	
	/* Replace this program by a new instance of the shell */
	execl(shell, shell, NULL);
	
	/* We should never get here, so it's an error. */
	fprintf(stderr, "Error starting shell\n");
	return 2;
}
When you run this, the program will exit by starting a new shell that will have the changed PATH. However, the previous shell you started the program from is still running as well. (and the new one will have a different commandline history as well). So if you start the program more than once, there will be a stack of shells running. you can verify this byt running it a few times, and then run:
Code:
/usr/bin/pstree | /bin/grep -B1 pstree
To prevent this, (and keep the same command line history) you need to run the program with "exec", like this:
Code:
exec ./my_program
If you run this a few times,and then check "/usr/bin/pstree | /bin/grep -B1 pstree", there will still be one shell running.

Hope this helps.

Last edited by Hko; 04-21-2004 at 05:29 PM.
 
Old 04-21-2004, 05:32 PM   #5
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
P.S. If changing environment variables is the only thing your program does, stick with jim mcnamara's solution. Much easier and more apropriate for just changing env. vars.
 
Old 04-22-2004, 12:24 AM   #6
itsme86
Senior Member
 
Registered: Jan 2004
Location: Oregon, USA
Distribution: Slackware
Posts: 1,246

Rep: Reputation: 59
You could just do this: system("VAR=setting; export VAR");
 
Old 04-22-2004, 11:58 AM   #7
jim mcnamara
Member
 
Registered: May 2002
Posts: 964

Rep: Reputation: 36
itsme - wont'work because system() forks (using exec) and creates a subprocess.

"export" only creates the variable for that process and any of it's children - not the parent process.

If a child could alter parent environments by using export, unix would have zero security.

Last edited by jim mcnamara; 04-22-2004 at 12:00 PM.
 
Old 04-22-2004, 07:00 PM   #8
aluser
Member
 
Registered: Mar 2004
Location: Massachusetts
Distribution: Debian
Posts: 557

Rep: Reputation: 43
Another way to handle this is to just have your program output shell commands to set the environment the way it wants it. e.g. ssh-agent is meant to be called like "eval `ssh-agent`"

The tricky part of this is that you need to output command appropriate to the shell you're using: csh and sh are a little different. You can check the SHELL environment variable of course.
 
Old 04-26-2004, 04:39 PM   #9
mvt
LQ Newbie
 
Registered: Apr 2004
Location: Lake City, Florida, USA
Distribution: Red Hat and SuSE
Posts: 9

Original Poster
Rep: Reputation: 0
Thanks for all the replies.

It looks like my original plan is simply not possible.

For closure, I finally used a method like that
proposed by "aluser":
eval `fixpath`
(recall that I am using tcsh)
where the name of my program is: fixpath
and the program writes a string like this to stdout:
set path=(/sbin /usr/bin)

It is not as clean as I had hoped for, but not too ugly.

Thanks 'aluser', for I didn't know about the eval
command.

Mark
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
setenv CLASSPATH ? mickeyboa Fedora 1 07-24-2005 05:26 PM
help with command setenv J0sep Red Hat 3 06-22-2004 07:52 PM
Setenv IBP Linux - Software 3 12-20-2002 10:05 AM
setenv DISPLAY toxic53 Linux - Newbie 2 09-27-2001 02:47 AM
setenv ???? toxic53 Linux - Networking 1 09-26-2001 12:30 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:15 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration