ECN No Name Newsletter: January, 1992

The ECN No Name Newsletter is no longer being published. This is an archived issue.

[previous article] [next article]

Using Hard-Coded Paths

David A. Curry

Many times, when writing shell scripts or C programs, it is necessary to build the path name to a file into your program. Most people do this by simply using the "hard-coded" path name, as in /home/iies/joe/barr/b/sue/bin/prmail . Unfortunately, this is a "dangerous" practice, particularly when the path refers to your home directory. For various reasons such as disk space consumption or hardware failures, it is sometimes necessary to move people's home directories. If this happens, then any program or shell script you have which uses hard-coded path names to your home directory (or someone else's) will break. Fortunately, there are more portable ways to encode path names into your shell scripts and C programs.

Shell Scripts

Within shell scripts, perhaps the simplest way to obtain the path name to your home directory in a portable manner is to use the $HOME environment variable. For example, to set your path in the Bourne shell (sh), you could replace the line

              PATH=/home/harbor/yourlogin/bin:$PATH

with the more portable line

                       PATH=$HOME/bin:$PATH

in your .profile .

In the C shell csh ), you can use the $HOME variable or the $home variable equivalently, allowing you to replace the line

               set path = (/b/yourlogin/bin $path)

with either of the lines

                   set path = ($HOME/bin $path)

                   set path = ($home/bin $path)

in your .cshrc .

A problem with the $HOME and $home notation occurs in scripts used by many people. The notation refers to the home directory of the person running the program, not the person who owns it. Thus, if you have a shell script that is used by several people, this notation may not work as you would like.

In the C shell, you can also use the tilde (~) character to refer to home directories. If followed by a login name, the construct ~login refers to the home directory of the user with login name login . If used without a login name, the tilde by itself refers to your home directory. Thus, to continue the path example from above, the following two lines are also equivalent:

      set path = (~/bin $path)

      set path = (~yourlogin/bin $path)

The tilde notation goes a long way toward solving the problem with the $HOME notation described above. Because you can indicate the login name of the user whose home directory you want, you can simply use the ~yourlogin construct in shell scripts that are used by people other than yourself, and things will still work properly.

There are some cases, unfortunately, where the $HOME and tilde constructs still will not do the job. In this case, you may still need to use hard-coded path names in your shell scripts. However, you can make things easier on yourself by putting those path names in shell variables and then referring to the variables throughout the script. A Bourne shell example of this is:

      #!/bin/sh

      LOGFILE=/home/jovian/bob/lib/logfile
      command > $LOGFILE

A C shell example looks like:



      #!/bin/csh

      set logfile = /b/mary/lib/logfile
      command > $logfile

C Programs

Within C programs, the same problems exist as described above, but the solutions are slightly different. To obtain the value of the $HOME variable described above, the getenv (3) library routine is used. This routine takes a character string as an argument - the name of the environment variable whose value you want. It returns a pointer to the value of that variable (in a character string), or NULL if the value could not be found. So, to make your program reference the file lib/logfile in your home directory in a portable manner, you might use code such as the following:



      #include 

      #define LOGFILE "lib/logfile"
      main()
      {
        FILE *fp;
        char logFileName[BUFSIZ];
        .....
        getLogfilePath(logFileName);
        fp = fopen(logFileName, "w");
        .....
      }

      /* Return path in buf */
      getLogfilePath(buf)
      char *buf;
      {
        char *p;
        char *getenv();

        p = getenv("HOME");
        if (p == NULL) {
          error("No $HOME\n");
          exit(1);
        }
        sprintf(buf, "%s/%s", p, LOGFILE);
      }

This code has the same problem with the use of the $HOME variable described above, though - the getenv("HOME") call will obtain the home directory of the person running the program, not the person who owns it. Thus, if more than one person is running the program, this may not do what you want.

To get around this, the getpwnam(3) library routine may be used instead. This routine takes a login name as an argument, and looks it up in the password file, returning a pointer to a structure with the password file line broken out into separate fields. The code above might be rewritten to use getpwnam as follows:

      #include 
      #include  /* for getpwnam */

      #define LOGIN   "yourlogin"
      #define LOGFILE "lib/logfile"
      main()
      {
        FILE *fp;
        char logFileName[BUFSIZ];
        .....
        getLogfilePath(logFileName);
        fp = fopen(logFileName, "w");
        .....
      }

      /* Return path in buf */
      getLogfilePath(buf)
      char *buf;
      {
        struct passwd *pwd;

        pwd = getpwnam(LOGIN);
        if (pwd == NULL) {
          error("%s not in passwd file.\n",
                LOGIN);
          exit(1);
        }
        /* Homedir is in pwd->pw_dir  */
        sprintf(buf, "%s/%s", pwd->pw_dir,
                LOGFILE);
      }


As with shell scripts, there are some cases where you just have to use hard-coded path names. Rather than putting them right in the code, it is better to use a #define macro to define the path. Furthermore, if you have several paths to define, it is best to put them all in one place, say a config.h include file. This way, if you do have to change things, you only need to edit one file and change each path a single time.

The important thing to remember when using hard-coded paths is that they can and do change from time to time. For example, when the next release of UNIX for the Suns comes out in 1992, it is likely that many home directory path names will be changing. You can deal with this in one of two ways - either make your programs more immune to the changes by using the information in this article, or spend a lot of time editing and recompiling every time things change.


webmaster@ecn.purdue.edu
Last modified: Thursday, 23-Oct-97 17:12:04 EST

[HTML Check] HTML