suaveant has asked for the wisdom of the Perl Monks concerning the following question:

I am working on a program that does things based on it's name... what I want to know is, can I find out how I was invoked? For instance if someone creates a symbolic link to me I would like to know.

the program is suid and ideally I'd like to allow symlinks by the Effective user, but no one else...

Arturo suggested file stat on $0 which only falls apart when the program is called from a PATH, so the directory info is not included. He suggested `which $0` as a way, maybe not the best, to get the info... anyone else have ideas?

Ideally I want to be able to do this in C and Perl, but Perl is fine for a start :)

                - Ant
                - Some of my best work - Fish Dinner

Replies are listed 'Best First'.
Re: Finding out how you were called...
by tadman (Prior) on Aug 07, 2001 at 01:07 UTC
    As far as I can tell, $0 will give you something to work with and from there you can figure out the rest. Based on my limited testing:
    • If the program was executed based on your $PATH, $0 will include the full pathname.
    • If the program was executed explicitly, either by being in the directory, or including a relative path, $0 is this relative path
    I think Perl is doing some fancy stuff to help you out there. After all, things often show up in the process table as having a "$0" of "perl foo" or "perl /path/to/foo", which correlates to the above two scenarios.

    In the event $0 does not include the full path for you, you can always "guess" which one was called by going through your $ENV{PATH} and testing each one:
    my $my_path = $0; foreach my $path (split(/:/, $ENV{PATH})) { $my_path = "$path/$0" if (-f "$path/$0"); }
    Either way, I think the functionality you are looking for is something like:
    my ($called_name) = $0 =~ m#/([^/]+)$#; { no strict; &{"mode_$called_name"}() if (defined &{"mode_$called_name"}); } sub mode_foo { # If program is called as "foo" } sub mode_moo { # If program is called as "moo" }
      Ahhh! $0 does... that's my bad for assuming argv[0] in c and $0 in perl contained the same values... is that just a perl thing, because it is a script called in the interpreter? How does perl find that data, and what is the way in C (If anyone knows... I realize this is perlmonks, not cmonks :) Thanks, tho... I want to do this in perl and C, but if it only works in perl, oh well :)

                      - Ant
                      - Some of my best work - Fish Dinner

        Don't feel bad. An entire module has sprung up based on this same misconception (and it was authored by some of the top Perl guys around). $0 is the name of the script, which Perl has to be able to open so Perl knows the correct path to it and doesn't hide it from you. argv[0] in the C code that implements Perl is "...perl" (not the script name) and may not have a full path and so $^X may not have a full path. See FindBin is broken (RE: How do I get the full path to the script executing?) for more.

                - tye (but my friends call me "Tye")
        It would seem that Perl processes its own argv[0] to make it all nice and easy for you to do what you want. This is not something that happens all by itself in C programs. C does, to a certain degree, leave you up to your own devices. So, evaluating your path for a possible match is something to consider doing, perhaps with strtok on a copy of your $PATH.
Re: Finding out how you were called...
by busunsl (Vicar) on Aug 07, 2001 at 10:14 UTC
    Have a look at the FindBin module.
    It will give you the called program or the real program with all links resolved.
Re: Finding out how you were called...
by rchiav (Deacon) on Aug 06, 2001 at 23:41 UTC
    $0 stores the name that the program was run as..

    Either I completely misread the question or you added the bit about $0 after I wrote this :)

    $0 (for me, on RH 7.1) contains the full path even if the script is in the path. The only time it doesn't is if I specify a relative path from the command line. An option could be to check, if it doesn't match the full path, if $0 and the pwd eq what you're looking for.

    Rich

      Since I can't edit SOPW posts... :)

      what I need is the command that was called, including the directory of it...

                      - Ant
                      - Some of my best work - Fish Dinner

      I assume that $0 is set by the shell, not by the OS... I have RH 7.1 with bash and I get exactly what was typed to run the command... i.e. foo ./foo /usr/bin/foo etc...

                      - Ant
                      - Some of my best work - Fish Dinner

        wierd.. I have RH 7.1 with bash (perl 5.61). Here's my test
        #!/usr/bin/perl -w print " I was called as $0\n";
        results as follows. tt is the original file. rr is a symlink in /usr/local/bin
        [xxxx@yyy:/home/xxxx]$ tt I was called as ./tt [xxxx@yyy:/home/xxxx]$ rr I was called as /usr/local/bin/rr [xxxx@yyy:/home/xxxx]$
Re: Finding out how you were called...
by princepawn (Parson) on Aug 06, 2001 at 23:35 UTC
  • maybe you could allow the different names to be calls to the same program name with commandline options. ie:
    Print_Users => mainprog --print-users Clear_users => mainprog --clear-users
  • Also, there was a batch queue system written in C called Autoson that did some crazy stuff with the way it was compiled so that different names to the same executable did different things.
      Actually what I am doing is executing a sub program by the same name as the executable... and it is supposed to be transparent, so command line options aren't good. But I don't want people to be able to ln -s a copy of the program to a different name and access a script they aren't supposed to.

                      - Ant
                      - Some of my best work - Fish Dinner