argv and argc, and just how to get them

argv and argc. They are vital parts of many programs. For the uninitiated, in many programming languages, they are the variables that hold the values typed into the commandline by the user. This article is about a particular problem we ran into trying to use them in a way that wasn’t really forseen. It really only applies to C and C++

Now most C/C++ programmers are probably thinking ‘what is so hard, you get them when you start main, right’…

int main(int argc,char **argv,char **envp)

That’s true, and in virtually all cases, you can store these values, either in a class, a global variable, a function, whatever your programming style uses. And from then on, you can simply access them from anywhere in the program. Its really simple, and something that most programmers know how to do in their sleep.

But what do you do before main happens? Or what about if you don’t have a main()

I know, you always have a main and nothing runs before it.

But that is very not true. Lets take two examples

Firstly, in C++

class gamedata
{
public:
  gamedata()
  {
    commandline=get_argv();
  }
  char **commandline;
}

static gamedata datastore;

int main(int argc,char **argv)
{
   set_argv(argv);
   ...
}

To start, this looks OK. Sure, Ive missed out a whole bunch of things, assumed what the user functions set_argv and get_argv do. But it looks fine. Until you look again. That static class instantiation will run its constructor before main runs. How on earth can you POSSIBLY get argv at this stage??

Lets look at an example in C now

If you are creating a shared object, you will very often need to initialise it to ensure that its state is known for the first call into the objects functions.

static char **commandline;

void __attribute__ ((constructor)) localinit()
{
  commandline=get_argv();
}

Again, you try this, and you get a big nothing. This function is called before main runs, before you ever have access to the values.

So, what is the answer?

The answer is, unfortunately, ugly. There is, in Linux, no good way of doing this. There are two perfectly good symbols inside libc which do the job perfectly, __libc_argv and __libc_argc, which are defined way before the program gets to any user-created code. Unfortunately they are declared private and you as a user are not permitted to see them. So, another way is needed.

We came up with two ways to make it work. Neither are portable, and one of them, while it works just fine, does make me go ewww. I’ll leave it to your imagination which one makes me go ewww the most.

char **get_argv()
{
  static char **preset_argv=NULL;

  if (!preset_argv)
  {
    FILE *fp;
    fp=fopen("/proc/self/cmdline","r");
    if (fp)
    {
      //Your implimentation to take the commandline as typed from this
      //file and turn it into argv. Its fairly basic
    }
  }
  return preset_argv;
}
char **get_argv()
{
  static char **preset_argv=NULL;

  if (!preset_argv)
  {
    extern char **environ;
    char ***argvp;
    void *p;
    asm ("mov %%esp, %0" : "=r" (p));
    argvp = p;
    while (*argvp != environ)
      argvp++;
    argvp--;
    preset_argv = *argvp;
  }
  return preset_argv;
}

So, a little explaination

The first example relies on /proc, the part of the filesystem that you can get all sorts of interesting information from. /proc/self/cmdline is always an exact duplicate of the command typed to execute the application, or the exact value passed in from the menu option you clicked to get it working. I haven’t bothered to create the bit of code to separate out the commandline parts onto their components. Partly because that code is fairly straightforwards, and partly because it is quite long and dull (remember it isn’t just a case of separating by spaces, you have to take into account things grouped in quotes, and other fun stuff). This is not portable beyond Linux, and people keep telling me that not all Linux distros have /proc either.

The second example requires a tiny bit of assembler knowledge. It is portable across most unix flavours, but I expect trying it outside of unix will cause you much pain. It relies on the fact that a unix standard is to push the argc and argv values right onto the top of the stack when a program starts. The example reads from the top of the stack until it finds the environ value (which is globally available at all times), and then reads back one value to get the pointer to argv. This way has the advantage that the values are correctly parsed for quotes and the like already. It makes the assumption that environ is the next thing on the stack after argv. I have seen many reports claiming this is always true, but I cannot find the location of an authoritative piece of documentation saying that it is specified true and will not change in future.

It isn’t often that you will need to do this. Most of the time, argv and argc are perfectly usable in the way you will probably have been using them for years. Even the examples above can be ‘worked around’ using initialisers called immediately after main() starts. But if one day, you come up against a problem where you need your argv where you usually don’t have access, I hope you find this post useful.

  • Share/Bookmark

Tags: , , , , , , ,

8 Responses to “argv and argc, and just how to get them”

  1. blindcoder says:

    Personally, I’d say the second…

  2. Edd says:

    Not that I like it any better, but do you really have to worry about quoting in /proc/*/cmdline? On mine it appears to be null delimited strings. I run:

    sleep ‘1′{2,1}’3′4 123

    and then look up the pid and run:

    tr “” “\n” < /proc//cmdline

    and see:

    sleep
    1234
    1134
    123

    It seems to me that, ugly as depending on /proc & reading this from a file interface is, reading the contents on cmdline as-is ought to be safe. If the contents of cmdline is not always that safe, then you have a(n other) compatibility issue.

    Edd

  3. titi says:

    I would simply use a second class for the start. Thats much better in my opinion and you have none of these problems.

    • Thats just the updates for the second release of Majesty – the one that has the copy protection in. Both versions will have the same features, but obviously binary patch deltas will need to be different

      • Max says:

        Boooh on the copy protection. Were there really so many people copying the games? I can’t understand how people can play games and at the same time copy them… either it’s bad and you don’t buy it or you like it and therefor buy it…

        Btw. What’s the deal with the “Please note: This site is fully moderated”? It’s new.

        And is Qwerty still with you?
        Personally I already had to retype some keys a few times… and I’d rather have saved that time. I yet got to test how the games react to not having a connection to the Internet.

        • Well, I explained the reasoning. I’ll be writing more about the copy protection in a post in the future.

          The new message is just to try and discourage people posting junk. We get 10-20 spams a day ever since I took out the capcha that people hated. It may have been hated but it really did work. The new one works a little, but only a little. I am tired of deleting them all so I thought it was worth mentioning they wont get through, just to try and discourage some of them. It hasnt changed how anything works, its always been moderated this way.

          The name qwerty didnt stick, we tries out the top 3, and she ended up as CatMonster. She’s still here, right now she’s sitting ontop of the scanner looking out of the window.

          How did you mean you had to retype some keys? You should only ever need to enter them once.

          • Max says:

            Nah, I definitely had to retype the one of X3 and also one for another game, but I can’t quite remember what the second one was. Also after the whole “re-registering”, the games were kind of “bugged”, e.g. the savegames for X3 were going crazy. (crashes right after loading, in the end I nailed it down to the quicksaves, the normal savegames worked) The bigger picture here might be some data corruption on the harddrive, causing this all, but I can’t imagine how it might have gotten corrupted and why nothing but those two games got affected. Well, the copy protection going crazy is just as unlikely as the data corruption that just affects the games… so it’ll probably remain an unsolved mystery forever. (well, even if the local data was corrupted, retyping the key would be strange, there are the… oh, well… thinking about it, there is no way to authenticate me towards the copy protection except for the cd key. The password is there to “unlock” the cd key and the email is there to recover a lost password (I’m not even sure if I entered an email adress)
            So if the local data got corrupted it somehow makes sense that I’d have to retype the Key)

            And seriously, if someone really wanted to “steal LGPs games”, couldn’t they just redirect the copy protections connections to their localhost selfmade authentication server? I doubt that it’s such a grant miracle to figure out how your copy protection works.
            Sure, I understand the move, but in the end it’s people like me who have to suffer from this. I never pirated ANY game at all off the Internet, back in the floppy days I occasionally copied games and I guess I also did in the CD age, although I don’t really remember burning any copies of game CDs, well, I know that I “pirated” Startopia from a video rental back when it was released, but then I bought the game after two days…
            I never copied a single game DVD. This also makes me remember how I rented “Commandos” every Saturday back in the days, till I had played through it. It probably payed as much as I would have payed for buying the game…

            While writing this I tried to understand your point of view and had to think of the 2dboys anniversary sale where you can pay as much as you want. (I already bought the game for 20 when the Linux version was released and at this sale I bought a copy for 5 for one of my brothers)
            When I saw the figures that they released I was kind of shocked. The majority of the people who participated in the action just payed 1 cent.
            (And that cent essentially went to Paypal, so the guys saw nothing…)
            So seeing how people abuse such actions and want everything for free, I guess I can see how the copy protection is kind of needed.
            I never regretted paying the 20 dollars for World of Goo. It was worth it’s money for sure. It kept me entertained for like… well, I can’t quite say for how long, but after I bought it I played it every evening in that week and then I did not touch it for a while and one day I finished it.
            But well… it surely kept me entertained longer than a movie in the cinema, which costs just as much.
            On the other hand I can’t understand how someone would pay 20 dollar for Mystic Mines. Well, maybe it’s just a thing of personal preferences, because even if I’d get it for free I’d probably not really play it. I’d take a look at it to check out the game concept (the whole pushing one button thing there) and then it’d drift off into the data nirvana.

            Well, to sum it up, I can’t stand copy protections and I can’t stand software pirates. Also I guess I rather put up with the copy protection system, than not seeing any games anymore for Linux.

            And I’m sorry for the bracket mess and the novel length.
            Also make sure to pat CatMonster for me. :P

Leave a Reply

To stop spam, please answer this simple question
What OS do we make games for

Please note: This site is fully moderated