您正在查看: 服务器 分类下的文章

chapter 4


Chapter 4

4.1

If stat is called, it always tries to follow a symbolic link (Figure 4.17), so the program will never print a file type of "symbolic link." For the example shown in the text, where /dev/cdrom is a symbolic link to cdroms/cdrom0 (which itself is a symbolic link to ../scsi/host0/bus0/target0/lun0/cd), stat reports that /dev/cdrom is a block special file, not a symbolic link. If the symbolic link points to a nonexistent file, stat returns an error.

4.2

All permissions are turned off:

  $ umask 777
  $ date > temp.foo
  $ ls -l temp.foo
  ----------  1 sar  0 Feb 5 14:06 temp.foo
4.3

The following shows what happens when user-read permission is turned off:

  $ date > foo
  $ chmod u-r foo  turn off user-read permission
  $ ls -l fooverify the file's permissions
  --w-r--r--  1 sar 29 Feb5 14:21 foo
  $ cat foo  and try to read it
  cat: foo: Permission denied
4.4

If we try, using either open or creat, to create a file that already exists, the file's access permission bits are not changed. We can verify this by running the program from Figure 4.9:

  $ rm foo bardelete the files in case they already exist
  $ date > foocreate them with some data
  $ date > bar
  $ chmod a-r foo bar turn off all read permissions
  $ ls -l foo bar  verify their permissions
  --w-------1 sar  29 Feb 5 14:25 bar
  --w-------1 sar  29 Feb 5 14:25 foo
  $ ./a.out  run program from Figure 4.9
  $ ls -l foo bar  check permissions and sizes
  --w-------1 sar  0 Feb5 14:26 bar
  --w-------1 sar  0 Feb5 14:26 foo

Note that the permissions didn't change but that the files were truncated.

4.5

The size of a directory should never be 0, since there should always be entries for dot and dot-dot. The size of a symbolic link is the number of characters in the pathname contained in the symbolic link, and this pathname must always contain at least one character.

4.7

The kernel has a default setting for the file access permission bits when it creates a new core file. In this example, it was rw-r--r--. This default value may or may not be modified by the umask value. The shell also has a default setting for the file access permission bits when it creates a new file for redirection. In this example, it was rw-rw-rw-, and this value is always modified by our current umask. In this example, our umask was 02.

4.8

We can't use du, because it requires either the name of the file, as in

  du tempfile

or a directory name, as in

  du .

But when the unlink function returns, the directory entry for tempfile is gone. The du . command just shown would not account for the space still taken by tempfile. We have to use the df command in this example to see the actual amount of free space on the file system.

4.9

If the link being removed is not the last link to the file, the file is not removed. In this case, the changed-status time of the file is updated. But if the link being removed is the last link to the file, it makes no sense to update this time, because all the information about the file (the i-node) is removed with the file.

4.10

We recursively call our function dopath after opening a directory with opendir. Assuming that opendir uses a single file descriptor, this means that each time we descend one level, we use another descriptor. (We assume that the descriptor isn't closed until we're finished with a directory and call closedir.) This limits the depth of the file system tree that we can traverse to the maximum number of open descriptors for the process. Note that the ftw function as specified in the XSI extensions of the Single UNIX Specification allows the caller to specify the number of descriptors to use, implying that it can close and reuse descriptors.

4.12

The chroot function is used by the Internet File Transfer Program (FTP) to aid in security. Users without accounts on a system (termed anonymous FTP) are placed in a separate directory, and a chroot is done to that directory. This prevents the user from accessing any file outside this new root directory.

In addition, chroot can be used to build a copy of a file system hierarchy at a new location and then modify this new copy without changing the original file system. This could be used, for example, to test the installation of new software packages.

Only the superuser can execute chroot, and once you change the root of a process, it (and all its descendants) can never get back to the original root.

4.13

First, call stat to fetch the three times for the file; then call utime to set the desired value. The value that we don't want to change in the call to utime should be the corresponding value from stat.

4.14

The finger(1) command calls stat on the mailbox. The last-modification time is the time that mail was last received, and the last-access time is when the mail was last read.

4.15

Both cpio and tar store only the modification time (st_mtime) on the archive. The access time isn't stored, because its value corresponds to the time the archive was created, since the file has to be read to be archived. The -a option to cpio has it reset the access time of each input file after the file has been read. This way, the creation of the archive doesn't change the access time. (Resetting the access time, however, does modify the changed-status time.) The changed-status time isn't stored on the archive, because we can't set this value on extraction even if it was archived. (The utime function can change only the access time and the modification time.)

When the archive is read back (extracted), tar, by default, restores the modification time to the value on the archive. The m option to tar tells it to not restore the modification time from the archive; instead, the modification time is set to the time of extraction. In all cases with tar, the access time after extraction will be the time of extraction.

On the other hand, cpio sets the access time and the modification time to the time of extraction. By default, it doesn't try to set the modification time to the value on the archive. The -m option to cpio has it set both the access time and the modification time to the value that was archived.

4.16

The kernel has no inherent limit on the depth of a directory tree. But many commands will fail on pathnames that exceed PATH_MAX. The program shown in Figure C.3 creates a directory tree that is 100 levels deep, with each level being a 45-character name. We are able to create this structure on all platforms; however, we cannot obtain the absolute pathname of the directory at the 100th level using getcwd on all platforms. On linux 2.4.22 and Solaris 9, we can never get getcwd to succeed while in the directory at the end of this long path. The program is able to retrieve the pathname on FreeBSD 5.2.1 and Mac OS X 10.3, but we have to call realloc numerous times to obtain a buffer that is large enough. Running this program on FreeBSD 5.2.1 gives us

Figure C.3. Create a deep directory tree

#include "apue.h"
#include <fcntl.h>

#define DEPTH 100 /* directory depth */
#define MYHOME"/home/sar"
#define NAME "alonglonglonglonglonglonglonglonglonglongname"
#define MAXSZ 8192

int
main(void)
{
inti, size;
char *path;

if (chdir(MYHOME) < 0)
err_sys("chdir error");

for (i = 0; i < DEPTH; i++) {
if (mkdir(NAME, DIR_MODE) < 0)
err_sys("mkdir failed, i = %d", i);
if (chdir(NAME) < 0)
err_sys("chdir failed, i = %d", i);
}
if (creat("afile", FILE_MODE) < 0)
err_sys("creat error");

/*

  • The deep directory is created, with a file at the leaf.
  • Now let's try to obtain its pathname.
    */
    path = path_alloc(&size);
    for ( ; ; ) {
    if (getcwd(path, size) != NULL) {
    break;
    } else {
    err_ret("getcwd failed, size = %d", size);
    size += 100;
    if (size > MAXSZ)
    err_quit("giving up");
    if ((path = realloc(path, size)) == NULL)
    err_sys("realloc error");
    }
    }
    printf("length = %d\n%s\n", strlen(path), path);

exit(0);
}


 $ ./a.out
 getcwd failed, size = 1025: Result too large
 getcwd failed, size = 1125: Result too large
 ...33 more lines
 getcwd failed, size = 4525: Result too large
 length = 4610
the 4,610-byte pathname is printed here

We are not able to archive this directory, however, using either tar or cpio. Both complain of a filename that is too long.

4.17

The /dev directory has all write permissions turned off to prevent a normal user from removing the filenames in the directory. This means that the unlink fails.

chapter 5


Chapter 5

5.2

The fgets function reads up through and including the next newline or until the buffer is full (leaving room, of course, for the terminating null). Also, fputs writes everything in the buffer until it hits a null byte; it doesn't care whether a newline is in the buffer. So, if MAXLINE is too small, both functions still work; they're just called more often than they would be if the buffer were larger.

If either of these functions removed or added the newline (as gets and puts do), we would have to ensure that our buffer was big enough for the largest line.

5.3

The function call

printf("");

returns 0, since no characters are output.

5.4

This is a common error. The return value from getc and getchar is an int, not a char. EOF is often defined to be -1, so if the system uses signed characters, the code normally works. But if the system uses unsigned characters, after the EOF returned by getchar is stored as an unsigned character, the character's value no longer equals -1, so the loop never terminates. The four platforms described in this book all use signed characters, so the example code works on these platforms.

5.5

A 5-character prefix, a 4-character per process unique identifier, and a 5-character per system unique identifier (the process ID) equals 14 characters, the original UNIX System limit on the length of a filename.

5.6

Call fsync after each call to fflush. The argument to fsync is obtained with the fileno function. Calling fsync without calling fflush might do nothing if all the data were still in memory buffers.

5.7

Standard input and standard output are both line buffered when a program is run interactively. When fgets is called, standard output is flushed automatically.

chapter 6


Chapter 6

6.1

The functions to access the shadow password file on linux and Solaris are discussed in Section 6.3. We can't use the value returned in the pw_passwd field by the functions described in Section 6.2 to compare an encrypted password, since that field is not the encrypted password. Instead, we need to find the user's entry in the shadow file and use its encrypted password field.

On FreeBSD and Mac OS X, the password file is shadowed automatically. In the passwd structure returned by getpwnam and getpwuid, the pw_passwd field contains the encrypted password (only if the caller's effective user ID is 0 on FreeBSD, however).

6.2

The program in Figure C.4 prints the encrypted password on linux and Solaris. Unless this program is run with superuser permissions, the call to getspnam fails with an error of EACCES.

Figure C.4. Print encrypted password under Linux and Solaris

#include "apue.h"
#include <shadow.h>

int
main(void) /* Linux/Solaris version */
{
struct spwd *ptr;

if ((ptr = getspnam("sar")) == NULL)
err_sys("getspnam error");
printf("sp_pwdp = %s\n", ptr->sp_pwdp == NULL ||
ptr->sp_pwdp[


Under FreeBSD, the program in Figure C.5 prints the encrypted password if the program is run with superuser permissions. Otherwise, the value returned in pw_passwd is an asterisk. On Mac OS X, the encrypted password is printed regardless of the permissions with which it is run.

Figure C.5. Print encrypted password under FreeBSD and Mac OS X

#include "apue.h"
#include <pwd.h>

int
main(void) /* FreeBSD/Mac OS X version */
{
struct passwd *ptr;

if ((ptr = getpwnam("sar")) == NULL)
err_sys("getpwnam error");
printf("pw_passwd = %s\n", ptr->pw_passwd == NULL ||
ptr->pw_passwd[

6.5

The program shown in Figure C.6 prints the date in a format similar to date.

Figure C.6. Print the time and date in a format similar to date(1)

#include "apue.h"
#include <time.h>

int
main(void)
{
time_tcaltime;
struct tm*tm;
char line[MAXLINE];

if ((caltime = time(NULL)) == -1)
err_sys("time error");
if ((tm = localtime(&caltime)) == NULL)
err_sys("localtime error");
if (strftime(line, MAXLINE, "%a %b %d %X %Z %Y\n", tm) == 0)
err_sys("strftime error");
fputs(line, stdout);
exit(0);
}


Running this program gives us

$ ./a.outauthor's default is US/Eastern
Sun Feb 06 16:53:57 EST 2005
$ TZ=US/Mountain ./a.outU.S. Mountain time zone
Sun Feb 06 14:53:57 MST 2005
$ TZ=Japan ./a.outJapan
Mon Feb 07 06:53:57 JST 2005

appendix c.&nbsp; solutions to selected exercises


Appendix C. Solutions to Selected Exercises

    Chapter 1

    Chapter 2

    Chapter 3

    Chapter 4

    Chapter 5

    Chapter 6

    Chapter 7

    Chapter 8

    Chapter 9

    Chapter 10

    Chapter 11

    Chapter 12

    Chapter 13

    Chapter 14

    Chapter 15

    Chapter 16

    Chapter 17

    Chapter 18

    Chapter 19

    Chapter 20

    Chapter 21

chapter 1


Chapter 1

1.1

For this exercise, we use the following two arguments for the ls(1) command: -i prints the i-node number of the file or directory (we say more about i-nodes in Section 4.14), and -d prints information about a directory instead of information on all the files in the directory.

Execute the following:

$ ls -ldi /etc/. /etc/..-i says print i-node number
 162561 drwxr-xr-x  66 root  4096 Feb  5 03:59 /etc/./
2 drwxr-xr-x  19 root  4096 Jan 15 07:25 /etc/../
$ ls -ldi /. /..  both . and .. have i-node number 2
2 drwxr-xr-x  19 root  4096 Jan 15 07:25 /./
2 drwxr-xr-x  19 root  4096 Jan 15 07:25 /../
1.2

The UNIX System is a multiprogramming, or multitasking, system. Other processes were running at the time this program was run.

1.3

Since the ptr argument to perror is a pointer, perror could modify the string that ptr points to. The qualifier const, however, says that perror does not modify what the pointer points to. On the other hand, the error number argument to strerror is an integer, and since C passes all arguments by value, the strerror function couldn't modify this value even if it wanted to. (If the handling of function arguments in C is not clear, you should review Section 5.2 of Kernighan and Ritchie [1988].)

1.4

It is possible for the calls to fflush, fprintf, and vprintf to modify errno. If they did modify its value and we didn't save it, the error message finally printed would be incorrect.

1.5

During the year 2038. We can solve the problem by making the time_t data type a 64-bit integer. If it is currently a 32-bit integer, applications will have to be recompiled to work properly. But the problem is worse. Some file systems and backup media store times in 32-bit integers. These would need to be updated as well, but we still need to be able to read the old format.

1.6

Approximately 248 days.