[comp.unix.questions] Get process name w/o using argv[0] in C function?

manoj@hpldsla.sid.hp.com (Manoj Joshi) (07/31/90)

Is there a way to get the name of a process anywhere inside the source?
By name, I mean argv[0]. As an alternative, I can pass argv[0] as an
extra parameter from main() to every function in the program, but I 
think it is inefficient. Also, I do not think I want to use a global
and initialize it to argv[0] in body of main(), because I do not use
globals!

I know that getpid() and getppid() get me the process id and parent's
process id. From this I can scan thru the proc table in proc.h, and
get the process name as a string. But this may be non-portable C.
Note that __FILE__ does not solve my problem, because it does not return
the name of the final executable, but only the current source file.

Anyone find  out how to do this?

Manoj.

guy@auspex.auspex.com (Guy Harris) (08/01/90)

>Also, I do not think I want to use a global and initialize it to
>argv[0] in body of main(), because I do not use globals!

Perhaps you should start doing so.  The only portable alternatives are
1) use a global or 2) pass argv[0] all the way down.

>I know that getpid() and getppid() get me the process id and parent's
>process id.

In effect, the process ID *is* a global, although in most UNIX
implementations it's not accessible directly from user code.  So if
you're using "getpid()", you're already using a global; it just happens
to be hidden inside a routine (a routine in the kernel, in most
implementations).  If globals really offend you, you might want to hide
the global in question inside a function.... 

mpl@pegasus.ATT.COM (Michael P. Lindner) (08/01/90)

In article <9220003@hpldsla.sid.hp.com> manoj@hpldsla.sid.hp.com (Manoj Joshi) writes:
>Is there a way to get the name of a process anywhere inside the source?
	deleted
>think it is inefficient. Also, I do not think I want to use a global
>and initialize it to argv[0] in body of main(), because I do not use
>globals!
	deleted
>process id. From this I can scan thru the proc table in proc.h, and
>get the process name as a string. But this may be non-portable C.
	deleted
>Manoj.

No.  There is no way to do this.  I do not understand why you would rather
write code to scan through the proc table (which, incidentally, will require
a setuid or setgid for your program and introduce all sorts of security
risks) than use a global.  If you know your architecture, you can do a stack
trace on your process from inside to get to argv, but that is non-portable
and ugly, too (although I have a routine which does it - I like ugly things,
sometimes :^)  My recommendation: BREAK DOWN AND USE A GLOBAL.

Mike Lindner
attmail!mplindner

peter@ficc.ferranti.com (Peter da Silva) (08/02/90)

In article <9220003@hpldsla.sid.hp.com> manoj@hpldsla.sid.hp.com (Manoj Joshi) writes:
> Is there a way to get the name of a process anywhere inside the source?
> I do not think I want to use a global and initialize it to argv[0] in
> body of main(), because I do not use globals!

Why not? This is guaranteed global per-process static data. There is no
reason not to use a global.

> I know that getpid() and getppid() get me the process id and parent's
> process id. From this I can scan thru the proc table in proc.h, and
> get the process name as a string. But this may be non-portable C.

All this to avoid using a global? Especially considering that this will
not work unless you're running as root!
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
<peter@ficc.ferranti.com>

jonb@specialix.co.uk (Jon Brawn) (08/02/90)

Someone writes:

>Also, I do not think I want to use a global and initialize it to
>argv[0] in body of main(), because I do not use globals!

Try this sort of thing:

#include <stdio.h>	/* for NULL and printf */

char *ProgName();

main( argc, argv )
char **argv;
{
	ProgName( argv[0] );

	/*
	** Code of your choice entered here
	*/

	Funky1();
}

Funky1()
{
	printf("My name is '%s'\n",ProgName(NULL));
}

/*
** ProgName - if passed a name will save a (private) handle to the name passed.
** Regardless, it will return a pointer to the current name stored.
*/
char *ProgName( pname )
char *pname;
{
	static char *myname = NULL;

	if ( pname )
		myname = pname;
	return myname;
}

No guarantees - no liability accepted. Have fun!
---
Jon Brawn, Specialix, 3 Wintersells Road, Byfleet, Surrey, KT14 7LF, UK.
Tel: +44(0)9323-54254,	Fax:+44(0)9323-52781,	jonb@specialix.co.uk
or: {backbone}!mcsun!ukc!slxsys!jonb
``Once upon a time, not so very long ago, in a land, not so very far away''
-- 
Jon Brawn, Specialix, 3 Wintersells Road, Byfleet, Surrey, KT14 7LF, UK.
Tel: +44(0)9323-54254,	Fax:+44(0)9323-52781,	jonb@specialix.co.uk
or: {backbone}!mcsun!ukc!slxsys!jonb

jrw@mtune.ATT.COM (Jim Webb) (08/02/90)

In article <9220003@hpldsla.sid.hp.com>, manoj@hpldsla.sid.hp.com (Manoj Joshi) writes:
> Is there a way to get the name of a process anywhere inside the source?
> By name, I mean argv[0]. As an alternative, I can pass argv[0] as an
> extra parameter from main() to every function in the program, but I 
> think it is inefficient. Also, I do not think I want to use a global
> and initialize it to argv[0] in body of main(), because I do not use
> globals!

What's wrong with using a global?  You'd be amazed what the routine that
puts together main(argc,argv) in the first place does if the use of a
global frightens you :-)

> I know that getpid() and getppid() get me the process id and parent's
> process id. From this I can scan thru the proc table in proc.h, and
> get the process name as a string. But this may be non-portable C.

In System V at least, the name of the process is not stored in the process
table, but rather in the process's user block.  Finding the user block can
be quite machine specific.

If you _really really really_ don't want to use a global, you have two
options, in order of diminishing appeal:

1) run the ps command inside a pipe and read the result:

	char psbuf[64];
	char command[15];
	FILE *ps;
	
	/* I'm sure this could be done better in perl :-) */
	sprintf(psbuf,"ps -p%d|awk '{/PID/ {next} { print $4 }'",getpid());
	ps=popen(psbuf,"r");
	fgets(command,15,ps);
	pclose(ps);
	command[strlen(command)-1]=NULL; /* chop off the \n */


2) do what the ps command does yourself:

get your process id via getpid().

#ifdef i386:

run the sysi86(RDUBLK) system call to get the user block for your
process and use u.u_comm.

#ifdef u3b2:

run the sys3b(RDUBLK) system call to get the user block for your process
and use u.u_comm.

#ifdef anyotherSysVbox:

do a name search on /unix and get the addresses of the process (_proc) and
variable (_v) tables, or, checking the dates of /unix and /etc/ps_data and
using the addresses in the latter if it exists and is newer than /unix
(gain wizard points if you use this approach, which is mucho faster than
running nlist)

open /dev/kmem and seek to _v and get the size of the process table from
v.v_proc (gain some wizard points if you use v.ve_proc later on)

seek to _proc and then read thru this structure v.v_proc times (or until
you reach v.ve_proc) comparing proc.p_pid with your process id.  if you
don't find it, well, them's the breaks :-)

when found, figure out how to find the user block for this process.  hints
are to look thru the process's page table to find where it thinks the ublock
is (it is _virtually_ the same for each process).

seek to that location and read in the ublock and use u.u_comm.

obviously, this all must be done as a user that has read permissions
on /dev/kmem.....normally group sys will suffice.

-----

Note that these solutions are really wastes of time (especially after
you throw in error checking) since the information desired is already
available in the process.

Later,

-- 
Jim Webb                "Out of Phase -- Get Help"               att!mtune!jrw
                  "I'm bored with this....Let's Dance!"

jjones@casca.cs.uiuc.edu (Joel Jones) (08/03/90)

One reason one may not be able to use a global is
if the function that needs the process name
may be a library that is linked in.  One way of
accomplishing the goal (though inefficient) is
to do a getpid(2), and then do a popen(3) with
an argument of "ps -p pid ..."

  Joel Jones
  jjones@uiuc.edu
--
Joel Jones     As the advertisment for an exhibition on Leonardo da Vinci said,
jones@uiuc.edu "They called him a genius, a botanist, a demon, a philosopher, a
                practical joker, an eccentric, and a visionary.  No wonder he 
                was such a great engineer."

davecb@yunexus.YorkU.CA (David Collier-Brown) (08/04/90)

jonb@specialix.co.uk (Jon Brawn) writes:
>Try this sort of thing:
[function that saves argv[0] in a static]

   Er, that substitutes a globally callable function for a globally
referable variable.  Net gain? more code to do the same thing, value
is read-only.  
   Looks like a bad tradeoff unless you have an imposed religious
requirement to avoid global variables...

--dave
-- 
David Collier-Brown,  | davecb@Nexus.YorkU.CA, ...!yunexus!davecb or
72 Abitibi Ave.,      | {toronto area...}lethe!dave 
Willowdale, Ontario,  | "And the next 8 man-months came up like
CANADA. 416-223-8968  |   thunder across the bay" --david kipling

scott@nbc1.ge.com (Scott Barman) (08/04/90)

In article <9220003@hpldsla.sid.hp.com> manoj@hpldsla.sid.hp.com (Manoj Joshi) writes:
>Is there a way to get the name of a process anywhere inside the source?
>By name, I mean argv[0]. As an alternative, I can pass argv[0] as an
>extra parameter from main() to every function in the program, but I 
>think it is inefficient. Also, I do not think I want to use a global
>and initialize it to argv[0] in body of main(), because I do not use
>globals!

I cannot think of one rational or even irrational reason *not* to use
global variables.  Can you explain this to us?

Do yourself a favor, declare and global like:
		char	*progname;

and the first line in your program do:
		progname = argv[0];

and save yourself a lot of unnecessary problem--including the waste in
CPU time and disk access trying to read the proc table for something
that is just handed to you.  Then again, if you are running a Cray... :-)

-- 
scott barman				NBC Systems Development
scott@nbc1.ge.com			30 Rockerfeller Plaza, Room 1615W
{philabs,crdgw1}!nbc1!scott		New York, NY  10112	+1 212/664-2787
  (This does not represent any [un]official opinions of NBC or its affiliates)

chris@mimsy.umd.edu (Chris Torek) (08/04/90)

>>... I do not think I want to use a global and initialize it to argv[0]
>>in body of main(), because I do not use globals!

This is misguided zeal: not *all* globals are bad....

In article <53103@iuvax.cs.indiana.edu> sahayman@iuvax.cs.indiana.edu
(Steve Hayman) writes:
>If you really are determined not to use a global variable for style reasons,
>you can hide the information off in another module. [example deleted]

This merely replaces the global variable with a, or in this case, two,
global functions.

So when are globals okay?  In general, if the thing being manipulated
has to last for the entire duration of the program, and the thing's
structure is dictated entirely by the goal of the program (as opposed
to some specifics of the program's implementation), then a global is
probably reasonable.  If the thing need only be known in one place, or
just a few places, then a file-scope `static' is probably best.

The real trick is finding the proper abstractions.  In this case the
goal is to print messages that include the program's name, so maybe
the best thing is to make `print a message that includes the program's
name' a function.  This replaces one global (the program's name) with
another (the function that prints messages), but in the process it
reduces the overall complexity of the whole program: instead of

	fprintf(stderr, "%s: configuration file %s not readable: %s\n",
		progname, conffile, strerror(errno));
	exit(EXIT_FAILURE);

you might have something like

	bomb_out("configuration file %s not readable: %s\n",
	    conffile, strerror(errno));

The (concrete) `print this to stderr; exit' sequence has been replaced
with the (more abstract) `stop because of this error' sequence.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris
	(New campus phone system, active sometime soon: +1 301 405 2750)

guy@auspex.auspex.com (Guy Harris) (08/05/90)

>One reason one may not be able to use a global is
>if the function that needs the process name
>may be a library that is linked in.  One way of
>accomplishing the goal (though inefficient) is
>to do a getpid(2), and then do a popen(3) with
>an argument of "ps -p pid ..."

Which won't work if your "ps" doesn't support the "-p" option.

Another way of accomplishing the goal is to change the library routine
(your posting sure assumes the user is in a position to do that; if they
can't change the library routine, they sure can't make it do the
"getpid()" nor the "popen()") to either:

1) take the "process name" as an argument;

2) have another routine that the main program calls, with the "process
   name" as an argument, that sets some static variable;

3) assume a (horrors!) global.

These require a change to the library interface, but hey, there's no
such thing as a free lunch....

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/06/90)

In article <1990Aug4.051827.16438@nbc1.ge.com> scott@nbc1.GE.COM (Scott Barman) writes:
>I cannot think of one rational or even irrational reason *not* to use
>global variables.

Really?  I thought this was commonly taught in structured software development
courses.

jonb@specialix.co.uk (Jon Brawn) (08/06/90)

davecb@yunexus.YorkU.CA (David Collier-Brown) writes:

>jonb@specialix.co.uk (Jon Brawn) writes:
>>Try this sort of thing:
>[function that saves argv[0] in a static]

>   Er, that substitutes a globally callable function for a globally
>referable variable.  Net gain? more code to do the same thing, value
>is read-only.  
    ^^^^^^^^^^
Course its read only! When was the last time you wanted to change the name
that you where invoked as? Shouldn't be allowed!

There are often occasions when I would like to be able to label something
as read only (yeah, I could grock the MMU on my machine, create a page
entry, set the appropriate flags and stuff, but its a hell of a chore!).
Hiding data in statics within functions is a relatively easy way of
achieving the same net effect.

You can also use the same approach for controlling access to objects. Keep
the actual data storage within one .c file as a static, and have functions
within that file that can be callable from outside the file which do
error checking on their arguments (wow! what a concept - error checking!)
before asigning to the object in question.

It also means that you can change the algorithm within the module at any
time, change the shape of the data, and still maintain the same interface
to the rest of the code. It would be perfectly possible to re-write the
routine I posted so that it did scan the proc table for the program name,
and still not have to change a single line of the main program. Or perhaps
a line could be added to the function which only saved the last part of
the programs name, stripping of any leading path. (e.g. store "myprog" rather
than "/usr/jonb/ace_progs/myprog"). Or perhaps it could store the name in
EBCDIC rather than ASCII (perhaps for efficiancy reasons?)

>   Looks like a bad tradeoff unless you have an imposed religious
>requirement to avoid global variables...

Hmm. I remember getting 0% for a piece of course work at college for using
a GOTO statement in Pascal, because it wasn't the sort of thing one did
in Pascal. Religious convictions? Possibly a more open outlook on future
trends....maybe the global will go the same way as the goto (I can but
hope).

What if the original question had been about something somewhat larger than
the program name? where would you stand then? Look at the streams routines -
compare them with the routines for clists. Whereas the cblock manipulation
was left mainly to the programmer (forming linked lists and all that) the
streams interface has lots of little functions to do it for you. Nuff said?

>--dave
--Jon.
-- 
Jon Brawn, Specialix, 3 Wintersells Road, Byfleet, Surrey, KT14 7LF, UK.
Tel: +44(0)9323-54254,	Fax:+44(0)9323-52781,	jonb@specialix.co.uk
or: {backbone}!mcsun!ukc!slxsys!jonb
``Once upon a time, not so very long ago, in a land, not so very far away''

richard@aiai.ed.ac.uk (Richard Tobin) (08/06/90)

In article <1990Aug2.143551.7104@specialix.co.uk> jonb@specialix.co.uk (Jon Brawn) writes:

>>Also, I do not think I want to use a global and initialize it to
>>argv[0] in body of main(), because I do not use globals!

>Try this sort of thing:

>char *ProgName( pname )

Why is a global function preferable than a global variable?

-- Richard
-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin

tif@doorstop.austin.ibm.com (Paul Chamberlain) (08/07/90)

In article <1990Aug6.115204.20113@specialix.co.uk> jonb@specialix.co.uk (Jon Brawn) writes:
>davecb@yunexus.YorkU.CA (David Collier-Brown) writes:
>>   Er, that substitutes a globally callable function for a globally
>>referable variable.  Net gain? more code to do the same thing, value
>>is read-only.  
>    ^^^^^^^^^^
>Course its read only! When was the last time you wanted to change the name
>that you where invoked as? Shouldn't be allowed!

Humorous mis-interpretation here.  Try "the value of this is change is only
visual."  I agree that by using the function calls to save/retrieve the
program name, you have eliminated the global.  But this much effort for
such a trivial function is IMNHO inappropriate for anything besides a
class-room.

The strict rules of a class-room have been discussed here many times.  And
IMNHO they teach important large-project habits using near-trivial examples
due to the time limitations.  I think they expect you to eventually forget
these really really strict rules (for the small projects) but then remember
them when they are really necessary for the large-project stuff.

Is there a comp.edu group for the ensuing flames?

Paul Chamberlain | I do NOT represent IBM         tif@doorstop, sc30661@ausvm6
512/838-7008     | ...!cs.utexas.edu!ibmaus!auschs!doorstop.austin.ibm.com!tif

george@hls0.hls.oz (George Turczynski) (08/08/90)

In article <13491@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <1990Aug4.051827.16438@nbc1.ge.com> scott@nbc1.GE.COM (Scott Barman) writes:
> >I cannot think of one rational or even irrational reason *not* to use
> >global variables.
> 
> Really?  I thought this was commonly taught in structured software development
> courses.

Yes, it is, as a principle, to discourage people from using
globals and no locals, as they might have gotten used to with
such things as BASIC.  It develops the ideas of information
hiding and so on.

The use of NO globals is however, only adopted by extremists.
As has been pointed out by someone already, the information
pertaining to the name of a process is GLOBAL BY DEFINITION,
and cannot be accessed except by direct or indirect use of
a global.  No way around it.

George P. J. Turczynski.          | ACSnet: george@highland.oz
                                  | Phone: 61 48 683490
Computer Systems Engineer.        | Fax:   61 48 683474
                                  |----------------------
Highland Logic Pty. Ltd.          | I can't speak for the
Suite 1, 348-354 Argyle Street    | company, I can barely
Moss Vale. NSW. 2577 Australia    | speak for myself...

jak@sactoh0.UUCP (Jay A. Konigsberg) (08/10/90)

In article <837@hls0.hls.oz> george@hls0.hls.oz (George Turczynski) writes:
>In article <13491@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>> In article <1990Aug4.051827.16438@nbc1.ge.com> scott@nbc1.GE.COM (Scott Barman) writes:
>> >I cannot think of one rational or even irrational reason *not* to use
>> >global variables.
>> 
>> Really? I thought this was commonly taught in structured software development
>> courses.
>
>Yes, it is, as a principle, to discourage people from using
>globals and no locals, as they might have gotten used to with
>such things as BASIC.  It develops the ideas of information
>hiding and so on.
>
>The use of NO globals is however, only adopted by extremists.
>

Yes, this is correct. In fact, there are some cases where the only
way to do something is *with* globals - though these situtations are
rare, they do exist. Also, there are times when you want something
to be global to a set of functions. For example the getch() & ungetch()
functions in K&R where the buf[] and bufp vars are shared.

Another case where globals are required involves the use of a signal
catcher() routine. If this routine needs information other than the
signal number, the only way to get it there is via a global (when
invoked by catching the signal that is). The case where I used this
was returning from "raw" to "cooked" char mode. The catcher() routine
had to reset ICANON and a couple of termio.??? values to their original
form.

Accucally, if things like globals and the neferious "goto" were really
_that_ bad, they wouldn't be included in the language. The fact of the
matter is though, sometimes they are needed. Just have good and
supportable reasons for using them.

-- 
-------------------------------------------------------------
Jay @ SAC-UNIX, Sacramento, Ca.   UUCP=...pacbell!sactoh0!jak
If something is worth doing, its worth doing correctly.

gt0178a@prism.gatech.EDU (BURNS,JIM) (08/11/90)

in various articles by (Jay A. Konigsberg),(George Turczynski),(Doug Gwyn),
& (Scott Barman):
>>> >I cannot think of one rational or even irrational reason *not* to use
>>> >global variables.
>>> Really? I thought this was commonly taught in structured software development
>>> courses.
>>Yes, it is, as a principle, to discourage people from using
>>globals and no locals, as they might have gotten used to with
>>such things as BASIC.  It develops the ideas of information
>>hiding and so on.
>>The use of NO globals is however, only adopted by extremists.
> Yes, this is correct.
[Discussion in defense of globals in certain cases.]

 I understood the current emphasis was on not MODIFYING globals in
 subroutines, as this is a side-effect, and can be hard to debug for future
 code maintainers, unless the usage of globals is carefully documented in
 comments sections. It's much cleaner to pass a global as a parameter than
 to let subs modify them (& some say even to access them, since later
 programmers may say "Well, I'm using it anyway - Why can't i modify it?"),
 since it's more obvious you intended for the sub to have access to the
 variable.

 The only time it is critical that subs not reference globals (other than
 system globals such as errno) is in canned library packages, which can't
 1) be dependent on the proper global environment being correctly setup,
 and 2) use global names internally that may collide with global names you
 have defined.

 Of course, the classic text-book example on using globals for information
 hiding is in writing massage routines for a small internal database. All
 you want to do is pass the data/key to be operated on, and the operation
 itself. You do NOT want to pass around the data structures for the database
 itself, so that the massagers will be free to change the implementation
 when database growth demands a reorganization of data or access method.
 (If you pass n arrays as the database in every call to the massage
 routines, you have to track down every one of those calls if the database
 structure changes.) '#include'-ing the appropriate set of global 'extern's
 in only the massage routines hides the database structure from the rest of
 the program.

 And then you have (SysV) Fortran programmers like me that are working on
 parent/child programs (some 78 in my system) where the only efficient
 solution to data sharing is some sort of IPC. I'm defining my COMMON to be
 in shared memory (HP-UX).
-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu