Section 4.22. chdir, fchdir, and getcwd Functions

team bbl


4.22. chdir, fchdir, and getcwd Functions

Every process has a current working directory. This directory is where the search for all relative pathnames starts (all pathnames that do not begin with a slash). When a user logs in to a UNIX system, the current working directory normally starts at the directory specified by the sixth field in the /etc/passwd filethe user's home directory. The current working directory is an attribute of a process; the home directory is an attribute of a login name.

We can change the current working directory of the calling process by calling the chdir or fchdir functions.

 #include <unistd.h> int chdir(const char *pathname); int fchdir(int filedes);

Both return: 0 if OK, 1 on error


We can specify the new current working directory either as a pathname or through an open file descriptor.

The fchdir function is not part of the base POSIX.1 specification. It is an XSI extension in the Single UNIX Specification. All four platforms discussed in this book support fchdir.

Example

Because it is an attribute of a process, the current working directory cannot affect processes that invoke the process that executes the chdir. (We describe the relationship between processes in more detail in Chapter 8.) This means that the program in Figure 4.23 doesn't do what we might expect.

If we compile it and call the executable mycd, we get the following:

     $ pwd     /usr/lib     $ mycd     chdir to /tmp succeeded     $ pwd     /usr/lib 

The current working directory for the shell that executed the mycd program didn't change. This is a side effect of the way that the shell executes programs. Each program is run in a separate process, so the current working directory of the shell is unaffected by the call to chdir in the program. For this reason, the chdir function has to be called directly from the shell, so the cd command is built into the shells.

Figure 4.23. Example of chdir function
 #include "apue.h" int main(void) {      if (chdir("/tmp") < 0)          err_sys("chdir failed");      printf("chdir to /tmp succeeded\n");      exit(0); } 

Because the kernel must maintain knowledge of the current working directory, we should be able to fetch its current value. Unfortunately, the kernel doesn't maintain the full pathname of the directory. Instead, the kernel keeps information about the directory, such as a pointer to the directory's v-node.

What we need is a function that starts at the current working directory (dot) and works its way up the directory hierarchy, using dot-dot to move up one level. At each directory, the function reads the directory entries until it finds the name that corresponds to the i-node of the directory that it just came from. Repeating this procedure until the root is encountered yields the entire absolute pathname of the current working directory. Fortunately, a function is already provided for us that does this task.

 #include <unistd.h> char *getcwd(char *buf, size_t size);

Returns: buf if OK, NULL on error


We must pass to this function the address of a buffer, buf, and its size (in bytes). The buffer must be large enough to accommodate the absolute pathname plus a terminating null byte, or an error is returned. (Recall the discussion of allocating space for a maximum-sized pathname in Section 2.5.5.)

Some older implementations of getcwd allow the first argument buf to be NULL. In this case, the function calls malloc to allocate size number of bytes dynamically. This is not part of POSIX.1 or the Single UNIX Specification and should be avoided.

Example

The program in Figure 4.24 changes to a specific directory and then calls getcwd to print the working directory. If we run the program, we get

     $ ./a.out     cwd = /var/spool/uucppublic     $ ls -l /usr/spool     lrwxrwxrwx 1 root 12 Jan 31 07:57 /usr/spool -> ../var/spool 

Note that chdir follows the symbolic linkas we expect it to, from Figure 4.17but when it goes up the directory tree, getcwd has no idea when it hits the /var/spool directory that it is pointed to by the symbolic link /usr/spool. This is a characteristic of symbolic links.

Figure 4.24. Example of getcwd function
   #include "apue.h"   int   main(void)   {       char    *ptr;       int     size;       if (chdir("/usr/spool/uucppublic") < 0)           err_sys("chdir failed");       ptr = path_alloc(&size); /* our own function */       if (getcwd(ptr, size) == NULL)           err_sys("getcwd failed");       printf("cwd = %s\n", ptr);       exit(0);   } 

The getcwd function is useful when we have an application that needs to return to the location in the file system where it started out. We can save the starting location by calling getcwd before we change our working directory. After we complete our processing, we can pass the pathname obtained from getcwd to chdir to return to our starting location in the file system.

The fchdir function provides us with an easy way to accomplish this task. Instead of calling getcwd, we can open the current directory and save the file descriptor before we change to a different location in the file system. When we want to return to where we started, we can simply pass the file descriptor to fchdir.

    team bbl



    Advanced Programming in the UNIX Environment
    Advanced Programming in the UNIX Environment, Second Edition (Addison-Wesley Professional Computing Series)
    ISBN: 0321525949
    EAN: 2147483647
    Year: 2005
    Pages: 370

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net