[comp.sys.ibm.pc] Environment settings from a C program

mark@hsi.UUCP (Mark Sicignano) (10/09/87)

I am trying to change an environment variable from within 
a Turbo-C program.  Turbo-C provides a function, putenv()
which will make changes to, add, or delete environment,
but any changes are made to the environment within the program,
and for child processes.

I need for these changes to remain.  Is it possible?

-mark
-- 
    
Net  :  {uunet|ihnp4|yale}!hsi!mark
Snail:  Health Systems Int'l, 100 Broadway, New Haven, CT 06511
Bell :  (203) 562-2101  ext. 32

ljz@fxgrp.UUCP (Lloyd Zusman) (10/11/87)

In article <700@hsi.UUCP> mark@hsi.UUCP (Mark Sicignano) writes:
>I am trying to change an environment variable from within 
>a Turbo-C program.  Turbo-C provides a function, putenv()
>which will make changes to, add, or delete environment,
>but any changes are made to the environment within the program,
>and for child processes.
>
>I need for these changes to remain.  Is it possible?


Sorry, but what you want to do isn't possible.  DOS (be it MSDOS or PCDOS)
is written such that no running program can change the environment of its
parent.  In case you need more explanation, consider this:

When you are at the command level of DOS (i.e., when you are entering commands
at the terminal), you are actually in a running program.  When you run a
C program (or whatever), DOS causes the program running at the command level
to suspend, and it starts up another program running as a "child" program.
This child is somewhat akin to a subprogram.  So, using this terminology,
the DOS command processor is a "parent" to your C program.  Every time DOS
starts up a child, it copies the parent's environment into a new area and
that becomes the child's environent.  Hence, any changes you make to the
child's environment have no effect on the parent's environment.  The main
use of putenv() is so that your C program can start its own child process and
pass altered or new values of its environment down to it.  This would be
done by calling putenv() and then calling one of the spawn() functions.

Lloyd Zusman
...!ames!fxgrp!ljz

psfales@ihlpe.ATT.COM (Pete Fales) (10/12/87)

In article <114@fxgrp.UUCP>, ljz@fxgrp.UUCP (Lloyd Zusman) writes:
> In article <700@hsi.UUCP> mark@hsi.UUCP (Mark Sicignano) writes:
> >I am trying to change an environment variable from within 
> >a Turbo-C program.  Turbo-C provides a function, putenv()
> >which will make changes to, add, or delete environment,
> >but any changes are made to the environment within the program,
> >and for child processes.
> >
> >I need for these changes to remain.  Is it possible?
> 
> 
> Sorry, but what you want to do isn't possible.  DOS (be it MSDOS or PCDOS)
                                 ^^^^^^^^^^^^^^
> is written such that no running program can change the environment of its
> parent.  In case you need more explanation, consider this:
> 

This is rather strong language for an operating system with no memory
protection.  I have 512 byte program downloaded from a bulletin board
called SETVAR.COM that does exactly that.  You type SETVAR XXX and
one line of standard input is put into XXX in the PARENT environment.  I
don't know how it works, but it is really nifty.  It provides
many of the same functions as back-quote substitution under UNIX.

Since the file is small, and news won't let me post this article
without more text, here is the uuencoded SETVAR.ARC.

begin 644 SETVAR.ARC
M&@A3151605(N0T]-  2^0@$  "8*E$H"^P "   ,Z0H!@%3@ST! *[8I\@ (
MP*!] >H,2(</0"(/!0(8.Q0(0(]%%B@ <"3,Q"(/+!SN U"GP2)M2QP-,S' 
MPP"'PP0LFJ:$I$D'-Z.%$THT7"*@ 62N^+?HVZ)H.WP,"#!G":P>Z&"Q)-+T
MZ9-%#C+ZZCC 1L9^\TS5\7:DJ=8!%C*B:P3 A(X"=1(LVF?"6 $ ZRQ  K#H
M'MBI*YXQ N8(VUY^\T@Q0M9XZ>$ N #4W5& CH$CXO"M@S*XK<T *[ZMP!C 
MCY!!ZP3XZ?'PCY\!NPSJ.A!@D3Q$'&@I:!9"E@): HC+:*>(20! ^0#0T6#$
MR")O3\&*%00 ,JE%\Q8IBYP9P"I:3$ A"$!\KWA^\EP-&_(&3AXY:<Z@H0,"
MQ9@4(,20 PXT@"!&'B 0$88<<N3!!@A%N ""%'6(D88; _D &@A3151605(N
M1$]#  2^/0,  "8*O4I=N0 %   ,#10$! &IP)0B5*P$D0*B10L00][ R2,G
MS1DT=$"@&)("1(P<.&B $),'!)$P<N3D80.BB L04NJ(2>,FX,""5-"DF0,"
MCIPW9^2$:0-"3IDP9'C205,&Q!PZ8=R004D&!$TX=3)&K1IFSAR+;I2B"9/1
M3A@V=<H$I/,&Q-*F9=S82?/339NX95&F"2.&35,W0\M4?>/&+5,08]ZT:;,5
M!!N:95S85- 6TH D9@S_#5S5;$6^?D&0>5.&IYLW&<O@V4F'A=6,.Q$;)2M8
MLD#*!"]G3I-Q=&D0JEF[YFV5)YDR?ND(!M'8Z)C9RJO>X8U&,XB;!-R4N0/"
M+%JUMRL/R-G4\]Z^36.?3NU&N=&J--E:CSNW[MWV5LU@?VNTN)L3[+U1QT5%
MO:$8"&:\(<=KS$GU&D_>I65;0$7@,10<?ND  G!CH-&6<D_QX509='@&@D(,
M6;:#4X$QQ]-!5)RX4 \@TC'9$X4914<=<A0F7V*+;>4"D*[!B.*(=(@%5TH*
M^F4'<L#%4<=9:WUXF%]NG+$4"&]D]I93=%24I8M?G:%=5?)]:1YHX*$  @SY
M6;<F>H@)R$95ZXW4U'-'1<?E@EV5>28(*;P$0A(U*? E7V\\"9R%;6!81I$(
M':DCCV$U"!R3<C@)99<@T#"A DZ@UM129(%@Y$*BD68::@B^<>>#=0;IX&/:
M,2?'&77<9Z.B;=4!!QQE+#A&5Y,ZU988>Z)4AAEUL!'"AE.$D0=-9ZA:*:LU
MRM9G:0&%(5H:9IA1+%[=Z<6F85&!(,*J#%%1Q!14B& H>;'*<9<< ?%)&T_B
MSAF:"#6*P&Y&Q[J1)[/,C3%&:7,L-Y>X;P5$Q!-3N NCP4 RYJ";,,9Z)T^\
M ;QKKW@I%>RPQ2*&+*&CYA1;PGKVA!(=:8P1+4ILE%1'Q-"R1--(9'6(8!I^
M\93@@FU$B[.D 1DU!QR$10RP@S7.86@:+D1F6&Q,L0$'3V(471VS0#9%L1QI
M!<1&5+R&<49DD^'K$U!"$75'5ZW>X08;;R"UG!D_$?7E$$\T 445\C+$1!!.
M'%%%$$<4<9T"8D2;W-!B!"X'?(4-<1:Y"KJQEPLH-,%$$REH (D)&@ :&AH:
M&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
4&AH:&AH:&AH:&AH:&AH:&AH:&AH:
 
end
-- 
Peter Fales		UUCP:	...ihnp4!ihlpe!psfales
			work:	(312) 979-7784
				AT&T Information Systems, IW 1Z-243
				1100 E. Warrenville Rd., IL 60566

hollen@mana.megatek.uucp (Dion Hollenbeck) (10/12/87)

>In article <700@hsi.UUCP> mark@hsi.UUCP (Mark Sicignano) writes:
>I am trying to change an environment variable from within 
>a Turbo-C program.  Turbo-C provides a function, putenv()
>which will make changes to, add, or delete environment,
>but any changes are made to the environment within the program,
>and for child processes.
>
>I need for these changes to remain.  Is it possible?

If you have enough memory, how about not returning to the DOS command
processor by leaving your program, but by creating a child process and
running COMMAND.COM which would then be passed a copy of your expanded
environment?  Have not tried this since I don't need the capability, but
it seems a reasonable way to solve it if it works for you.
	Dion Hollenbeck             (619) 455-5590 x2814
	Megatek Corporation, 9645 Scranton Road, San Diego, CA  92121
			    ames!scubed!
		{sdcsvax,hplabs}!hp-sdd!megatek!hollen
			 sdcsvax!esosun!

acm@bu-cs.BU.EDU (ACM) (10/13/87)

In article <2168@ihlpe.ATT.COM> psfales@ihlpe.ATT.COM (Pete Fales) writes:
>In article <114@fxgrp.UUCP>, ljz@fxgrp.UUCP (Lloyd Zusman) writes:
>> In article <700@hsi.UUCP> mark@hsi.UUCP (Mark Sicignano) writes:
>> >I am trying to change an environment variable from within 
>> >a Turbo-C program.  Turbo-C provides a function, putenv()
>> >which will make changes to, add, or delete environment,
>> >but any changes are made to the environment within the program,
>> >and for child processes.
>> >
>> >I need for these changes to remain.  Is it possible?
>> 
>> 
>> Sorry, but what you want to do isn't possible.  DOS (be it MSDOS or PCDOS)
>                                 ^^^^^^^^^^^^^^
>> is written such that no running program can change the environment of its
>> parent.  In case you need more explanation, consider this:
>> 
>
>This is rather strong language for an operating system with no memory
>protection.

True.  The way you do it is look for the pointer to the parent's PSP
in your PSP.  I forget the actual address of the pointer -- anyone out
there know what it is?  Anyway, after you find the parent's PSP you can
get a pointer to the parent's environment and play with it as you
like.  it's not a bright idea to expand the environment because this
is likely to cause massive memory problems.  Expansion of the
environment MUST NOT exceed the last paragraph in the environment (or
the max size of the parent's environment -- in the case of COMMAND.COM
you have some idea of what this will be).  Normally you just setblock
the environment pointer, but I don't think you can do this if you're
playing with a parent process.

Another point is that it's easy to backtrace through all the programs
currently in memory with the pointer to the parent's PSP.  I've seen
some programs out there that do it -- nice to see what kind of stuff
you've got stuck in memory.

jim frost
madd@bucsb.bu.edu

dave@westmark.UUCP (Dave Levenson) (10/14/87)

In article <700@hsi.UUCP>, mark@hsi.UUCP (Mark Sicignano) writes:
> I am trying to change an environment variable from within 
> a Turbo-C program.  Turbo-C provides a function, putenv()
> which will make changes to, add, or delete environment,
> but any changes are made to the environment within the program,
> and for child processes.

In MS-DOS, as in UNIX, you can change your environment, and then
export it to your children, but you cannot change your parent's
environment.  You inherit a copy, and operate on it.

Unlike UNIX, however, MS-DOS cannot protect itself from applications
that disobey its rules.  If you can find out where your parent keeps
its environment, you can alter it.

The segment address of your environment block appears at offset 2C
in your PSP.  Offset 16 of your PSP contains the segment address of
your parent's PSP.  Offset 16 of your parent's PSP points at your
grandparent's PSP, and so on.  (The first PSP, belonging to
COMMAND.COM, points to itself!)

Offset 2C of your parent's PSP holds the segment address of your
parent's environment block.  You probably won't be able to get there
with putenv() but with enough chaining through enough far pointers,
you can probably accomplish what you want to.
-- 
Dave Levenson
Westmark, Inc.		A node for news.
Warren, NJ USA
{rutgers | clyde | mtune | ihnp4}!westmark!dave

paula@bcsaic.UUCP (Paul Allen) (10/15/87)

In article <700@hsi.UUCP>, mark@hsi.UUCP (Mark Sicignano) writes:
>I am trying to change an environment variable from within 
>a Turbo-C program.  Turbo-C provides a function, putenv()
>which will make changes to, add, or delete environment,
>but any changes are made to the environment within the program,
>and for child processes.
>
>I need for these changes to remain.  Is it possible?

I've seen several responses to this, ranging from "It's impossible" to
"here's a PD program that does it".  So far, noone has mentioned 
undocumented interrupt 1EH.  This interrupt takes as an argument a
pointer to a string containing a command to be executed by command.com.
The first byte of the string is a count of the remaining bytes.  If you
pass it "set foo=bar", it will set the variable foo in command.com's
environment space.  A little thought will turn up all sorts of nifty
uses for this capability.  In fact, one of my unfinished projects at
home is a little program that understands commands like !!, history,
and alias, and passes everything it doesn't understand off to command.com.

Caveats:

I have used this undocumented feature, and it works, but it is probably
undocumented for a reason.  I am working from memory, or I could tell
you which register to put the string address in.  If you really want it,
e-mail me.  Or check Ray Duncan's column in back issues of Dr. Dobb's or
the Best of BIX column in back issues of BYTE.

Paul Allen
paula@boeing.com
...!uw-beaver!ssc-vax!bcsaic!paula

wew@naucse.UUCP (Bill Wilson) (10/16/87)

You cannot make changes to the environmemt without knowing where
it is housed in memory.  Good luck, I haven't found out where
it is yet.

paula@bcsaic.UUCP (Paul Allen) (10/17/87)

This is an update to my recent posting (2400@bcsaic.UUCP) describing the
back-door interface to command.com.  As usual, posting from memory has
gotten me into trouble!  I was describing interrupt 2EH, *not* interrupt
1EH!  From the current BYTE "Inside the IBM PCs" special issue, page
168, comes the following data:

Undocumented interrupt 2EH causes command.com to execute a command
pointed to by ds:si.  The first byte of the command is the number of
bytes in the command.  The command must end with a carriage return, just
as if it had been typed on the keyboard.  The article is not clear on
whether the cr is included in the byte count.  So, to change something
in command.com's environment, a small model program could simply
construct the command, put its ds-relative offset in si, and do an int
2EH.  One side-effect of this technique is that any output from the
command will go to command.com's stdout (the screen).  Another poster
described a way to change command.com's environment by following the
chain of parent PSP pointers until you find command.com's.  Passing "set
foo=bar" to int 2EH seems considerably easier to me.  Int 2EH has been
described in depth in Ray Duncan's column in Dr. Dobb's Journal.  There
may also have been information in BYTE's "Best of BIX" column.  I have
used it on MSDOS 2.1.  I seem to remember that one of Ray Duncan's
articles claimed it would work on everything since version 2.0, but you
ought to check that out for yourself.

Paul Allen
paula@boeing.com
...!uw-beaver!ssc-vax!bcsaic!paula

darrylo@hpsrlc.HP.COM (Darryl Okahata) (10/17/87)

In comp.sys.ibm.pc, paula@bcsaic.UUCP (Paul Allen) writes:

> In article <700@hsi.UUCP>, mark@hsi.UUCP (Mark Sicignano) writes:
> >I am trying to change an environment variable from within 
> >a Turbo-C program.  Turbo-C provides a function, putenv()
> >which will make changes to, add, or delete environment,
> >but any changes are made to the environment within the program,
> >and for child processes.
> >
> >I need for these changes to remain.  Is it possible?
> 
> I've seen several responses to this, ranging from "It's impossible" to
> "here's a PD program that does it".  So far, noone has mentioned 
> undocumented interrupt 1EH.  This interrupt takes as an argument a
     [ ... ]
> Caveats:
> 
> I have used this undocumented feature, and it works, but it is probably
> undocumented for a reason.  I am working from memory, or I could tell
     [ ... ]
> 
> Paul Allen
> paula@boeing.com
> ...!uw-beaver!ssc-vax!bcsaic!paula
> ----------

     Int 2EH only seems to change the environment of the topmost
invocation of command.com.  For example, if you run another copy of
command.com, and run a program which changes the environment via Int 2EH,
you will find that the environment of the second copy of command.com has
not changed.  You will have to EXIT the second copy before the changes will
become visible.

     Also, if I remember correctly, Int 2EH destroys ALL registers,
including those of the STACK.  Yuk!

     -- Darryl Okahata
	{hplabs!hpccc!, hpfcla!} hpsrla!darrylo
	CompuServe: 75206,3074

Disclaimer: the above is the author's personal opinion and is not the
opinion or policy of his employer or of the little green men that
have been following him all day.

ljz@fxgrp.UUCP (Lloyd Zusman) (10/22/87)

With regard to using int 2Eh to cause the top-level command interpreter
to execute a command line ...

Yes, this can be used to set an environment variable in the top-level
command interpreter, but there are some caveats that may or may not
be important:

1)  This is an undocumented DOS call, meaning that it may go away or change.

2)  Once you use it to set an environment variable in the top-level command
    interpreter, the varible DOES NOT propagate down to all the children
    of this top-level interpreter.  In other words, assume I have booted up
    my PC and I'm sitting at the command prompt:

        C>

    I type SET and I get a list of environment variables containing the
    line

        FOO=BAR

    This means that there is a variable named FOO in my environment with
    the value BAR.  Now, suppose I have written a C program that contains
    the following code fragment ...

	extern char *getenv();
        char *ep = getenv("FOO");
	printf("FOO=%s\n", ep ? ep : "<NOT SET>");
	int1e("SET FOO=QUACK");
	ep = getenv("FOO");
	printf("FOO=%s\n", ep ? ep : "<NOT SET>");

    Assume that the int1e() function passes its string argument to int 1Eh
    properly.  The output of this program fragment will be

        FOO=BAR
        FOO=BAR

    It will NOT be

        FOO=BAR
        FOO=QUACK

    as you might hope.  But after the program returns control to DOS, the
    next time you type SET, you will see the line

        FOO=QUACK

    in your environment.  If you insert the following call after the int1e()
    call in the above program

        putenv("FOO=QUACK")

    then you will see the value of the variable FOO change during the
    course of running the program.

    To make it worse, suppose that from DOS I run a program that causes
    a subshell to run, and within this subshell, the above program is
    run (the version with the putenv()).  What will happen is that the
    top level environment will be changed (via the int 1Eh), the
    environment in effect while the program is running will be changed
    (via the putenv() call), but the environments for all processes
    inbetween these will stay the same.

    If this sort of thing is what you want, then int 1Eh is useful.
    Otherwise, be careful.

3)  I have had applications hang when making use of int 1Eh.  I think
    it might have to do with the amount of space taken up by TSR
    ("Terminate and Stay Resident") programs, the version of DOS that's
    being run, etc.  Be careful.

zu@ethz.UUCP (Urs Zurbuchen) (10/28/87)

In article <2434@bcsaic.UUCP> paula@bcsaic.UUCP (Paul Allen) writes:
> ... Another poster
>described a way to change command.com's environment by following the
>chain of parent PSP pointers until you find command.com's.  Passing "set
>foo=bar" to int 2EH seems considerably easier to me.

You forget one thing: Using Int 2Eh you can't set a variable to a string
longer than about 120 characters. The exact amount depends on the length
of the variablename. You only can execute commands of a total length of
128 (or 127) characters.


		...urs

UUCP: ...seismo!mcvax!cernvax!ethz!zu