rlj@ncsu.UUCP (Rick Johnson) (09/19/85)
Is it possible to set a csh environment variable within a C program? I know about getenv(), but have failed at attempts to set an environment variable from a C program. Basically, what I want to do is "source" a new environment variable for the current csh process. Any comments or suggestions would be appreciated. Thanks. -- Rick Johnson (decvax!mcnc!ncsu!rlj)
gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (09/22/85)
> Is it possible to set a csh environment variable within a C program? I know > about getenv(), but have failed at attempts to set an environment variable > from a C program. Basically, what I want to do is "source" a new environment > variable for the current csh process. Any comments or suggestions would be > appreciated. Thanks. There seems to be some confusion here. A program invoked from the shell is a child process of the shell, not "the current process". A child process cannot affect the environment of its parent, so the answer is "No". The environment is not a csh-specific concept; see ENVIRON(5 or 4).
tmb@talcott.UUCP (Thomas M. Breuel) (09/22/85)
In article <2936@ncsu.UUCP>, rlj@ncsu.UUCP (Rick Johnson) writes: > Is it possible to set a csh environment variable within a C program? I know > about getenv(), but have failed at attempts to set an environment variable > from a C program. Basically, what I want to do is "source" a new environment > variable for the current csh process. Any comments or suggestions would be > appreciated. Thanks. [I have heard this question before several times, and think that a posting is therefore warranted. It belongs in net.unix.] [see also execve(2) and environ(7)] The environment strings reside in a process' address space, which makes them inaccessible to any other process. It is therefore not possible for one process to change the environment variables of another process except at the time of creation of an immediate child, when the environment is passed as the third argument to the execve system call (other varieties of the exec system call (implemented as library functions) pass the environment data along automatically). Thomas.
myke@gitpyr.UUCP (Myke Reynolds) (09/23/85)
Well, the following program will pass a parent's environment variables to
a child. It nukes the first env var and replaces it with a new one.
What you want to do is change the internal variables of a parent process.
It will only do that if it wants to let you, there is no inherent way of
doing it. Note that setenv and set are shell commands, not executable
files..
---------------------------------------------------------------------------------
char *newvar = "newvar = (here I am !)";
main(argc, argv, envp)
char **argv, **envp;
{
envp[0] = newvar;
execle("/bin/csh", "csh", 0, envp);
}
--
Myke Reynolds
Office of Telecommunications and Networking
Georgia Insitute of Technology, Atlanta Georgia, 30332
...!{akgua,allegra,amd,hplabs,ihnp4,seismo,ut-ngp}!gatech!gitpyr!myke
"Too bad all the people that know how to run this country are busy cutting
hair and driving taxi cabs."
-George Burns
mouse@mcgill-vision.UUCP (der Mouse) (09/23/85)
> Is it possible to set a csh environment variable within a C program? I know > about getenv(), but have failed at attempts to set an environment variable > from a C program. Basically, what I want to do is "source" a new environment > variable for the current csh process. Any comments or suggestions would be > appreciated. Thanks. In general, this is possible theoretically (most UNIX systems) but impossible in practice. Now before you get disheartened, note that with a little cooperation from the shell this is quite feasible. There are at least two ways: (1) If the program doesn't want to print anything, have it just print the command the shell should execute and then use backquotes in the shell to catch this. Then you can "eval" it (you did say csh, didn't you...yes). (2) If the program wants to do printing, have it write a file on /tmp somewhere (eg, use getppid() to find the parent shell's PID and use that) that the shell can find (in the example, /tmp/$$ or some such). Then the "command" users see is actually an alias which runs the program, sources the temp file, and removes it. Something like that. If you aren't interested in hairy reasons or explanations, you can stop reading now. The reason for this is that there is no way provided for the C program to do anything to its parent process, such as modifying the environment stored there. The reason it's possible theoretically is that (theory only, note) the C program can go poking around in the kernel tables (via /dev/kmem or equivalent) and find out where the shell process lives (in memory or on swap) and modify it directly (via /dev/mem or /dev/drum or equivalent). This requires more privilege than user programs usually have in the first place and it would be difficult, if not impossible, to avoid timing problems (it's on swap, ok, clock ticks and it's in memory, but we still think it's on swap). I've tried to redirect followups to net.unix (hope it works, this is the first time I've tried to do that). -- der Mouse {ihnp4,decvax,akgua,etc}!utcsri!mcgill-vision!mouse philabs!micomvax!musocs!mcgill-vision!mouse Hacker: One responsible for destroying / Wizard: One responsible for recovering it afterward
mash@mips.UUCP (John Mashey) (09/23/85)
Rick Johnson (decvax!mcnc!ncsu!rlj) writes: > Is it possible to set a csh environment variable within a C program? I know > about getenv(), but have failed at attempts to set an environment variable > from a C program. Basically, what I want to do is "source" a new environment > variable for the current csh process. Any comments or suggestions would be > appreciated. Thanks. I assume that you're not interested in just modifying the current environment, [which is fairly straightforward, and has been posted somewhere in last 6 months], but in getting changes back to the parent shell [csh or sh]. You can't modify the parent shell's environment directly, but only by returning a character string to be "eval"ed. Suppose C pgm "glurp" ends with: printf("setenv a b\n"); Invoke it with: eval `glurp` to set a = b. More complex effects can be gotten by changing the printf string. A process cannot modify its parent's environment, on purpose. At one point, such a feature was considered, and rejected, because it had no simple, understandable semantics. For example, many otherwise deterministic computations turn nondeterministic, depending on process scheduling. Consider a pipeline like a | b | c, where all of a, b, c could modify their parent's environment, or worse, nohup a& (and logoff). [Exactly what is a modifying?] -- -john mashey UUCP: {decvax,ucbvax,ihnp4}!decwrl!mips!mash DDD: 415-960-1200 USPS: MIPS Computer Systems, 1330 Charleston Rd, Mtn View, CA 94043
cottrell@nbs-vms.ARPA (COTTRELL, JAMES) (09/24/85)
/* > Is it possible to set a csh environment variable within a C program? I know > about getenv(), but have failed at attempts to set an environment variable > from a C program. Basically, what I want to do is "source" a new environment > variable for the current csh process. Any comments or suggestions would be > appreciated. Thanks. In a word NO! There is no way to affect your parent's environment unless they made prior arrangements (like before you were born) to do so. Sounds kinda like Life, doesn't it? A way to do this is to set up an alias which runs your program, then sources a file which the program builds. Try the following: alias z 'echo setenv QAZ WSX > EDC ; source EDC' Now type `printenv;z;printenv'. Note the change! Another method might be: setenv NAME `prog` if you only want you change ONE variable & you know it's name. If you want to change more, you can always do: set x = `prog` ; $x I don't know why `prog` by itself on a line doesn't work. Probably because `...` only returns one word. Oh well... jim cottrell@nbs */ ------
david@ukma.UUCP (David Herron, NPR Lover) (09/25/85)
> > Is it possible to set a csh environment variable within a C program? I know > > about getenv(), but have failed at attempts to set an environment variable > > from a C program. Basically, what I want to do is "source" a new environment > > variable for the current csh process. Any comments or suggestions would be > > appreciated. Thanks. As many people have said, it ain't possible to set your parents' environment (that is, short of such self-abuse as poking around in /dev/mem). However, it *is* possible to do it for your children. See my posting in net.sources for more information. -- --- David Herron --- ARPA-> ukma!david@ANL-MCS.ARPA --- UUCP-> {ucbvax,unmvax,boulder,oddjob}!anlams!ukma!david --- {ihnp4,decvax,ucbvax}!cbosgd!ukma!david Hackin's in me blood. My mother was known as Miss Hacker before she married!
pdg@ihdev.UUCP (P. D. Guthrie) (09/25/85)
>Rick Johnson (decvax!mcnc!ncsu!rlj) writes: >> Is it possible to set a csh environment variable within a C program? I know >> about getenv(), but have failed at attempts to set an environment variable >> from a C program. Basically, what I want to do is "source" a new environment >> variable for the current csh process. Any comments or suggestions would be >> appreciated. Thanks. > >A process cannot modify its parent's environment, on purpose. At one point, >such a feature was considered, and rejected, because it had no simple, >understandable semantics. For example, many otherwise deterministic >computations turn nondeterministic, depending on process scheduling. >Consider a pipeline like a | b | c, where all of a, b, c could modify >their parent's environment, or worse, nohup a& (and logoff). [Exactly >what is a modifying?] >-- >-john mashey >UUCP: {decvax,ucbvax,ihnp4}!decwrl!mips!mash >DDD: 415-960-1200 >USPS: MIPS Computer Systems, 1330 Charleston Rd, Mtn View, CA 94043 What about implementing some type of library function and corresponding shell commands that would load and save an "environment", including perhaps aliases, sort of like Carnegie-Mellon's PCL-Exec for Tops-20. This would enable someone to modify the environment from a program and then have the shell load it in, so file locking could be used to guard against multiple modifications. I guess this capability crudely exists with the source command, but I was thinking of something at a lower level with less command interpretation. I really liked PCL-Exec, and something with that power would be great on Unix. Perhaps a signal could be used to notify a process that it has a new environment? Paul Guthrie.
rs@mirror.UUCP (09/25/85)
> Is it possible to set a csh environment variable within a C program? Presumably you want to do something like the BSD "tset" program, which SEEMS LIKE it adds environment variables to its parent's process. The only way to do this is to have your program write out a command line that can be "sourced" in. For example, this program: main() { int p; if (p = fork()) printf("setenv CLOCKPID %d ; echo clock...", p), exit(0); ...print a clock on the status line every once in a while... } You can now add the pid of the clock "daemon" by doing something like this: CSH SH EITHER clock >/tmp/$$ clock >/tmp/$$ eval `clock` source /tmp/$$ . /tmp/$$ rm /tmp/$$ rm /tmp/$$ Note that if your environment variables contain shell meta-characters, you might have problems (only CSH, I think). -- Rich $alz {mit-eddie, ihnp4!inmet, wjh12, cca, datacube} !mirror!rs Mirror Systems 2067 Massachusetts Ave. 617-661-0777 Cambridge, MA, 02140
jpn@teddy.UUCP (09/27/85)
> Is it possible to set a csh environment variable within a C program? In all the replies to this question, I have not yet seen my favorite techniqe. This only works on BSD 4.X (at least as far as I know). There is an undocumented ioctl() which allows you to push data back onto your input queue (i.e. simulate characters typed at the terminal). Using this technique, one can stuff strings like "setenv TERM xxx\n" into the parent shell's input. A fragment of the code that does the work: #include <sgtty.h> eatthis(string) register char *string; { int pendin = LPENDIN; noecho(); /* turn off echo mode */ while (*string) { ioctl(0, TIOCSTI, string); /* do the work */ ++string; } echo(); /* turn echo back on */ ioctl(0, TIOCLBIS, &pendin); /* set the pending input flag */ }
tmb@talcott.UUCP (Thomas M. Breuel) (09/29/85)
In article <1355@teddy.UUCP>, jpn@teddy.UUCP writes: > > Is it possible to set a csh environment variable within a C program? > > In all the replies to this question, I have not yet seen my favorite techniqe > This only works on BSD 4.X (at least as far as I know). There is an > undocumented ioctl() which allows you to push data back onto your input queue > (i.e. simulate characters typed at the terminal). Using this technique, one > can stuff strings like "setenv TERM xxx\n" into the parent shell's input. The ioctl is documented in tty(4). Generally, your program is unlikely to be smart enough to type at whatever I invoke it from (e.g. shell escape from ed). Use of this ioctl can cause extremely weird behaviour of programs and shell scripts. Since it is also non-portable, works only on ttys and might be abolished altogether, I would strongly recommend *not* to use it. Thomas.
pdg@ihdev.UUCP (P. D. Guthrie) (09/30/85)
>I don't know why `prog` by itself on a line doesn't work. Probably >because `...` only returns one word. Oh well... > > jim cottrell@nbs >*/ >------ Because "eval `prog`" exists.
pdg@ihdev.UUCP (P. D. Guthrie) (09/30/85)
In article <1355@teddy.UUCP> jpn@teddy.UUCP (John P. Nelson) writes: >> Is it possible to set a csh environment variable within a C program? > >In all the replies to this question, I have not yet seen my favorite techniqe. >This only works on BSD 4.X (at least as far as I know). There is an >undocumented ioctl() which allows you to push data back onto your input queue >(i.e. simulate characters typed at the terminal). Using this technique, one >can stuff strings like "setenv TERM xxx\n" into the parent shell's input. > >A fragment of the code that does the work: > >#include <sgtty.h> > >eatthis(string) >register char *string; > { > int pendin = LPENDIN; > > noecho(); /* turn off echo mode */ > while (*string) > { > ioctl(0, TIOCSTI, string); /* do the work */ > ++string; > } > echo(); /* turn echo back on */ > ioctl(0, TIOCLBIS, &pendin); /* set the pending input flag */ > } Undocumented? TTY(4) page 12 (66lines/page). This call does not exist on either System 5 or Version 7 - however the hack to put them into the kernel is about twenty lines. Oh for this and FIONREAD to be put into standard SYS V!!! Paul Guthrie.
chris@umcp-cs.UUCP (Chris Torek) (10/02/85)
TIOCSTI works, but is unweildy and not very general. In addition, you must be careful not to overflow the TTY input queue. Here is a program I wrote long ago for saving and restoring C shell history in, well, an `unusual fasion' which works around the latter problem. #include <stdio.h> #include <sgtty.h> #include <ctype.h> main(argc, argv) int argc; register char **argv; { register char *hp, *cp; register FILE *in; register total = 0; static char histbuf[BUFSIZ], cmd[BUFSIZ + 5] = "!#:p "; struct sgttyb tty, otty; if (argc != 2) { fprintf(stderr, "Usage: %s file\n", argv[0]); exit(1); } if ((in = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[1]); exit(1); } if (ioctl(0, TIOCGETP, &tty) < 0) { fprintf(stderr, "%s: not connected to a tty\n", argv[0]); exit(1); } switch (fork()) { case -1: fprintf(stderr, "%s: fork failed\n", argv[0]); exit(1); case 0: break; default: exit(0); } otty = tty; tty.sg_flags &= ~ECHO; (void) ioctl(0, TIOCSETN, &tty); while (fgets(histbuf, sizeof histbuf, in)) { if (cmd[5]) { for (cp = cmd; *cp; cp++) (void) ioctl(0, TIOCSTI, cp); if ((total += cp - cmd) >= 100) {/* fudge factor */ sleep(1); total = 0; } } cp = cmd + 5; hp = histbuf; if (hp[6] == '\t' && isdigit(hp[5])) hp += 7; while (*cp++ = *hp++); } /* * Note: drop last command as it was the one that dumped the history * list. */ (void) ioctl(0, TIOCSETN, &otty); exit(0); } -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
mikel@codas.UUCP (Mikel Manitius) (10/06/85)
> /* > > Is it possible to set a csh environment variable within a C program? I know > > about getenv(), but have failed at attempts to set an environment variable > > from a C program. Basically, what I want to do is "source" a new environment > > variable for the current csh process. Any comments or suggestions would be > > appreciated. Thanks. > > In a word NO! There is no way to affect your parent's environment unless > they made prior arrangements (like before you were born) to do so. > Sounds kinda like Life, doesn't it? > > [ ... examples of kludges deleted ... ] Yet Another Way Neglected (kind of like YACC, but YAWN :-}): eval `prog` have "prog" generate the following output: set home=/usr/mikel setenv FOOBAR dodo For further usage of eval, consult your manuals. -- ======= Mikel Manitius ==----===== AT&T (305) 869-2462 RNX: 755 ==------===== Information Systems ...{akguc|ihnp4}!codas!mikel ===----====== SDSS Regional Support ...attmail!mmanitius =========== Altamonte Springs, FL My opinions are my own. =======
mouse@mcgill-vision.UUCP (der Mouse) (10/09/85)
> >> Is it possible to set a csh environment variable within a C program? > > > >In all the replies to this question, I have not yet seen my favorite techniqe. > >This only works on BSD 4.X (at least as far as I know). There is an > >undocumented ioctl() which allows you to push data back onto your input queue > >(i.e. simulate characters typed at the terminal). Using this technique, one > >can stuff strings like "setenv TERM xxx\n" into the parent shell's input. > > [[[ code using TIOCSTI omitted ]]] > > Undocumented? TTY(4) page 12 (66lines/page). This call does not exist > on either System 5 or Version 7 - however the hack to put them into the > kernel is about twenty lines. Oh for this and FIONREAD to be put into > standard SYS V!!! How right you are. TIOCSTI is one of the neatest features around. (Maybe not heavily used, but neat.) However, I must take issue with > > Using this technique, one can stuff strings like "setenv TERM xxx\n" > > into the parent shell's input. You can't, in general. All you can do is stuff stuff back into the terminal input stream, which is not always the shell's input stream (shell scripts etc). Besides, guess what it can do to typeahead: login: mouse Password: Last login etc.... /etc/motd etc.... cd foo em % % setenv TEaRM xxx emsetenv: Command not found. % cs test.c cs: Command not found. Well, maybe I notice in time not to hit the last newline. Besides, that isn't what it looks like because I hacked upon my shell to give supersmart line editing (and I don't use "%" for my prompt). Tsk tsk. Please try to be more precise in the future. <admonishing frown, and in case someone didn't notice, (:-)> -- der Mouse {ihnp4,decvax,akgua,etc}!utcsri!mcgill-vision!mouse philabs!micomvax!musocs!mcgill-vision!mouse Hacker: One responsible for destroying / Wizard: One responsible for recovering it afterward