1
• Communicating intimacy vs. communicating verbal messages
• Lovers’ cups, drinking interfaces
(MIT media Lab)
• Emotional (Crying) Décor (NYU)
• Interactive Pillow (TII, Sweden)
• Hand holding (Cornell)
2
• Do you feel confused in the classroom?
• Do you feel bored in the classroom?
• Do you feel ignored in the classroom?
• Do you feel unfairness that only the speaker has control of the slides?
• Now … you can express frustration with the Active Slides!
3
• Objectives
– Additional Features of the File System
– Properties of a File.
• Three major functions:
#include <sys/types.h>
#include <sys/stat.h> int stat(const char *pathname, struct stat *buf); int fstat(int filedes, struct stat *buf); int lstat(const char *pathname, struct stat *buf);
4
• Differences on stat(), fstat(), lstat():
– lstat() returns info regarding the symbolic link, instead of the referenced file, if it happens.
struct stat { mode_t st_mode; /* type & mode */ ino_t st_ino; /* i-node number */ dev_t st_dev; /* device no (filesystem) */ dev_t st_rdev; /* device no for special file */ nlink_t st_nlink; /* # of links */ uid_t st_uid; gid_t st_gid; off_t st_size; /* sizes in byes */ time_t st_atime; /* last access time */ time_t st_mtime; /* last modification time */ time_t st_ctime; /* time for last status change */ long st_blk_size; /* best I/O block size */ long st_blocks; /* number of 512-byte blocks allocated */
};
5
• Encoded in st_mode
• Regular Files: text, binary, etc.
• Directory Files: Only Kernel can update these files –
{ (filename, pointer) }.
• Character Special Files, e.g., tty, audio, etc.
• Block Special Files, e.g., disks, etc.
• FIFO – named pipes
• Sockets – not POSIX.1 or SVR4
– SVR4 uses library of socket functions, instead. 4.3+BSD has a file type of socket.
• Symbolic Links – not POSIX.1 or SVR4
6
S_ISREG() // regular file
S_ISDIR()
S_ISCHR()
S_ISBLK()
S_ISFIFO()
S_ISLNK()
S_ISSOCK()
7
#include "apue.h"
{
Int main(int argc, char *argv[]) int struct stat char buf;
*ptr; i; for (i = 1; i < argc; i++) { printf("%s: ", argv[i]); if (lstat(argv[i], &buf) < 0) { err_ret("lstat error"); continue;
} if (S_ISREG(buf.st_mode)) ptr = "regular "; else if (S_ISDIR(buf.st_mode)) ptr = "directory";
} else if (S_ISCHR(buf.st_mode)) ptr = "character special"; if (S_ISBLK(buf.st_mode)) ptr = "block special"; else if (S_ISFIFO(buf.st_mode)) ptr = "fifo"; else if (S_ISLNK(buf.st_mode)) ptr = "symbolic link"; else if (S_ISSOCK(buf.st_mode)) ptr = "socket"; else ptr = "** unknown mode **"; printf("%s\n", ptr);
} exit(0);
8
• All files have access permissions
– st_mode mask – owner, group, other
#define S_IRWXU 00700 /* read, write, execute: owner */
#define S_IRUSR 00400 /* read permission: owner */
#define S_IWUSR 00200 /* write permission: owner */
#define S_IXUSR 00100 /* execute permission: owner */
#define S_IRWXG 00070 /* read, write, execute: group */
#define S_IRGRP 00040 /* read permission: group */
#define S_IWGRP 00020 /* write permission: group */
#define S_IXGRP 00010 /* execute permission: group */
#define S_IRWXO 00007 /* read, write, execute: other */
#define S_IROTH 00004 /* read permission: other */
#define S_IWOTH 00002 /* write permission: other */
#define S_IXOTH 00001 /* execute permission: other */
9
• File Operations: read, write, execute, etc.
• File Access Permissions: who (process) can perform what operations
• Directory file
– X – pass through the dir (search bit), e.g., /usr/dict/words.
– R – list of files under the dir.
– W – update the dir, e.g., delete or create a file.
• Regular file
– X – execute a file (which must be a regular file)
– R – O_RDONLY or O_RDWR
– W – O_WRONLY, O_RDWR, or O_TRUNC
• What are the needed file access permissions?
– ls /home/professor/hchu
– cd /home/professor/hchu
– rm /home/professor/hchu/foo
– cat /home/professor/hchu/foo
– echo 123 >> /home/professor/hchu/foo
10
• How to check if a process can perform an operation on file access permissions?
– File access test: check (process IDs, file APs, OP)
• A process can have more than one ID.
– Real user/group ID // who we really are, e.g., hchu
– Effective user/group ID // used for file access
// permission checks
– Supplementary group IDs
– Saved set-user/group-ID // saved by exec function
11
• File Access Test – each time a process creates/opens/deletes a file
– If the effective UID == 0 superuser!
– If the effective UID == UID of the file
• Check appropriate access permissions!
– If the effective GID == GID of the file
• Check appropriate access permissions!
– Check appropriate access permissions for others!
• Related Commands: chmod & umask
12
hchu@linux1:/> ls -l /etc/shadow
-rw-r----- 1 root shadow 843 2006-03-07 10:01 /etc/shadow hchu@linux1:/> cat /etc/shadow hchu@linux1:/> ls -al .
drwxr-xr-x 22 root root 4096 2006-01-20 13:33 ./ drwxr-xr-x 22 root root 4096 2006-01-20 13:33 ../ drwxr-xr-x 2 root root 4096 2006-03-13 18:23 bin/ hchu@linux1:/> cd bin hchu@linux1:/usr/include> which passwd
/usr/bin/passwd hchu@linux1:/usr/include> ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 28224 2006-02-22 14:05 /usr/bin/passwd hchu@linux1:/usr/include> rm /usr/bin/passwd hchu@linux1:/usr/include> passwd
13
• st_mode: st_uid/st_gid
– Setting user/group ID of the owner.
• How can a user change his/her password without having the write permission to /etc/passwd and /etc/shadow?
-rw-r--r--
-r--------
1 root root 1746 2/21 13:00 /etc/passwd
1 root root 1142 2/21 13:01 /etc/shadow
• A process can have more than one ID.
– Real user/group ID
– Effective user/group ID
– Supplementary group IDs
– Saved set-user/group-ID
14
– UID of a file = the effective UID of the creating process
– GID of a file – options under POSIX
1.
GID of the file = the effective GID of the process
2.
GID of the file = the GID of the residing dir
– 4.3BSD and Mac OS X do (2).
– SVR4 needs to set the set-group-ID bit of the residing dir
(mkdir)!
15
• Test a file accessibility before accessing it.
#include <unistd.h> int access(const char *pathname, int mode);
– R_OK // test for read permission
– W_OK
– X_OK
– F_OK
– Check the real UID/GID!
16
#include "apue.h"
#include <fcntl.h>
}
{ int main(int argc, char *argv[]) if (argc != 2) err_quit("usage: a.out
<pathname>"); if (access(argv[1], R_OK) < 0) err_ret("access error for %s", argv[1]); else printf("read access OK\n"); if (open(argv[1], O_RDONLY) < 0) err_ret("open error for %s", argv[1]); else exit(0); printf("open for reading OK\n");
>ls -l fig4.8.exe
-rwxr-xr-x 1 hchu users 9487 2006-
03-21 19:53 fig4.8.exe
>fig4.8.exe fig4.8.exe
read access OK open for reading OK
>ls -l /etc/shadow
-rw-r----- 1 root shadow 843 2006-
03-07 10:01 /etc/shadow
>fig4.8.exe /etc/shadow access error for /etc/shadow:
Permission denied open error for /etc/shadow:
Permission denied
17
• Set file mode creation mask (default file permissions)
#include <sys/types.h>
#include <sys/stat.h> mode_t umask(mode_t cmask);
– Any bits that are on in the cmask are turned off in the file’s mode
• cmask = bitwise-OR file access permissions (e.g., S_I[RWX]USR)
• Examples: cmask = S_IRWXO, cmask = S_IWOTH | S_IWGRP
– The mask goes with the process only.
• Inheritance from the parent!
18
#include "apue.h"
#include <fcntl.h>
#define RWRWRW
(S_IRUSR|S_IWUSR|S_IRGRP|S_IW
GRP|S_IROTH|S_IWOTH)
}
{ int main(void) umask(0); if (creat("foo", RWRWRW) < 0) err_sys("creat error for foo"); umask(S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH); if (creat("bar", RWRWRW) < 0) exit(0); err_sys("creat error for bar");
>umask
22
>fig4.9.exe
>ls -al foo bar
-rw------- 1 hchu users 0 2006-03-21 20:14 bar
-rw-rw-rw- 1 hchu users 0 2006-03-21
20:14 foo
>umask
22
19
• Change file access permissions for an existing file.
#include <sys/types.h>
#include <sys/stat.h> int chmod(const char *pathname, mode_t mode); int fchmod(int filedes, mode_t mode);
– fchmod() is not in POSIX.1, but in SVR4/4.3+BSD
– Callers must be a superuser or effective UID = file UID.
– Mode = bitwise-OR S_I[RWX]USR, S_ISVTX (sticky bit), S_IS[UG]ID, etc (Fig 4.6).
20
}
#include "apue.h"
{
Int main(void) struct stat statbuf;
/* turn on set-group-ID and turn off group-execute */ if (stat("foo", &statbuf) < 0) err_sys("stat error for foo"); if ( chmod("foo", (statbuf.st_mode &
~S_IXGRP) | S_ISGID) < 0) err_sys("chmod error for foo");
/* set absolute mode to "rw-r--r--" */ if ( chmod("bar", S_IRUSR | S_IWUSR |
S_IRGRP | S_IROTH) < 0) err_sys("chmod error for bar"); exit(0);
>ls -al foo bar
-rw------- 1 hchu users 0 2006-03-21
20:14 bar
-rw-rw-rw- 1 hchu users 0 2006-03-21
20:14 foo
>fig4.12.exe
>ls -al foo bar
-rw-r--r-- 1 hchu users 0 2006-03-21
20:14 bar
-rw-rwSrw- 1 hchu users 0 2006-03-
21 20:14 foo
// what is strange here?
21
– If the GID of a newly created file is not equal to the effective GID of the creating process (or one of the supplementary GID’s), or the process is not a superuser, clear the set-group-ID bit!
– Clear up set-user/group-ID bits if a non-superuser process writes to a set-uid/gid file.
22
– For frequently executed binaries
– Not POSIX.1 – by SVR4 & 4.3+BSD
– Only superusers can set it!
– S_ISVTX executable file
• Used to save a copy of a S_ISVTX executable in the swap area to speed up the execution next time.
– S_ISVTX directory file, e.g., /tmp
• Remove/rename its file only if w permission of the dir is set, and the process is belonging to superusers/owner of the file/dir
23
• Change the user/group ID of a file
#include <sys/types.h>
#include <unistd.h> int chown(const char *pathname, uid_t owner, gid_t, grp); int fchown(int filedes, uid_t owner, gid_t, grp); int lchown(const char *pathname, uid_t owner, gid_t, grp);
– lchown() is unique to SVR4. Under non-SVR4 systems, if the pathname to chown() is a symbolic link, only the ownership of the symbolic link is changed.
– -1 for owner or grp if no change is wanted
.
• Why would one want to give away file ownership?
24
• _POSIX_CHOWN_RESTRICTED is in effect (check pathconf())
– Superuser the UID of the file can be changed!
– The GID of the file can be changed if
• the process owns the file, and
• Parameter owner = UID of the file & Parameter grp = the process
GID or is in supplementary GID’s
• set-user/group-ID bits would be cleared if chown is called by nonsuper users.
25
• File Sizes – st_size
– Regular files – 0~max (off_t)
– Directory files – multiples of 16/512
– Symbolic links – pathname length
– /* a pipe’s file size for SVR4 */
• File Holes
– st_blocks vs st_size (st_blksize)
– Commands:
• “ls –l file.hole” == “wc –c file.hole”
• du –s file.hole actual size
• cat file.hole > file.hole.copy
26
# include <sys/types.h>
#include <unistd.h> int truncate(const char *pathname, off_t length); int ftruncate(int filedes, off_t length);
– Not POSIX.1
– SVR4 creates a hole if length > fsize.
– 4.3+BSD only truncates files.
– Portability?
27
28
29
(Tokyo University)
30
• A disk can be divided into logical partitions.
• Each partition has a filesystem.
• Each filesystem contains a list of inodes (i-list) as well as the actual directory- and data blocks
• Every inode has a link count (st_nlink): it shows how many “things” point to this inode. Only if this link count is 0 are the data blocks freed. Each name
<-> inode association is called a hard link.
• inode contains most of information found in the stat structure.
• inode number in a directory entry must point to an inode on the same file system (no hardlinks across filesystems)
• To move a file within a single filesystem, we can just ”move” the directory entry (actually done by creating a new entry, and deleting the old one).
31
32
Figure 4.14 (hard links)
33
mode owner timestamp size block ref-count data data data
…
• 4KB block size
• 12 direct pointers
• 48KB
• 1 single indirect
• 4-byte block ptr
• 1K * 4KB = 4MB
• >> 4GB for the largest file!
(offset = 32 bits, 4G=2 32 ) direct blocks data single indirect double indirect
… data
… data
…
… data
… data triple indirect
… data
…
* “Operating system concept”, Silberschatz and Galvin, Addison Wesley, pp. 380.
34
(> mkdir testdir ; link count, leaf vs. intermediate dirs)
35
• Hard Link
– Cannot link to different mounted file system.
– is a different name for the same set of data blocks.
– Only superuser can create a link to a directory.
• Soft Link (or Symbolic link)
– Can be a directory or file
– Is a pointer to a set of data blocks.
– File type is S_IFLINK
• What’s the difference on their i-nodes?
36
/usr/joe foo
/usr/sue bar
/usr/joe foo
/usr/sue bar
File i-node:
#Reference = 2
File i-node:
#Reference = 1
File i-node:
#Reference = 1 data block:
“/usr/joe/foo”
• Hard Link
– Each directory entry creates a hard link of a filename to the i-node that describes the file’s contents.
– Normally require that link & file on the same file system
• Symbolic Link (Soft Link)
– It is implemented as a file that contains a pathname.
– Filesize = pathname length
– Example: Shortcut on
Windows
– Get around with filesystem limitation & linking dirs
37
/usr/joe foo
/usr/sue bar
/usr/joe foo
/usr/sue bar
File i-node:
Reference = 2
• Problems with links
– Infinite loops
– Dangling pointers
– Unable to remove
File i-node:
Reference = 1
File i-node:
Reference = 1 data block:
“/usr/joe/foo”
38
a foo testdir
> mkdir foo
> touch foo/a
> ln –s ../foo foo/testdir
> ls –l foo
> ls –R
• List subdirectories recursively foo foo/a foo/testdir foo/testdir/?
39
(> mv testdir testdir2 -> only update inode)
40
#include <unistd.h> int link(const char *existingpath, const char *newpath); int unlink(const char *pathname);
– Atomic action for link – hard link
• POSIX.1 allows linking across filesystems
• Only superusers could create a link to a dir
– Error if newpath exists
– Unlink – WX right at the residing dir
• Remove the dir entry & delete the file if link count reaches zero and no one still opens the file (Remark: sticky bit & dir rights).
41
– Open & unlink a file
#include "apue.h"
#include <fcntl.h>
}
{ int main(void) if (open("tempfile", O_RDWR) < 0) err_sys("open error"); if (unlink("tempfile") < 0) err_sys("unlink error"); printf("file unlinked\n"); sleep(15); printf("done\n"); exit(0);
42
– Sticky bits set for a residing dir, we must have the write permission for the directory and either owner of the file, the dir, or super users.
– If pathname is a symbolic link, unlink references the symbolic link.
43
#include <stdio.h> int remove(const char *pathname); int rename(const char *oldname, const char *newname);
– remove = rmdir if pathname is a dir. (ANSI C)
– Rename – ANSI C
• File: both files, newname is removed first, WX permission for both residing directories
• Directory: both dir, newname must be empty, newname could not contain oldname.
– > rename /usr/foo /usr/foo/testdir ???
44
#include <unistd.h>
– actualpath does not need to exist!
• They do not need to be in the same file system.
– readlink is an action consisting of open, read, and close – not null terminated.
45
• Three Time Fields:
Field Description st_atime last-access-time st_mtime last-modification-time st_ctime last-i-node-change-time
Example
Read
Write chmod, chown ls-option
-u default
-c
• Changing the access permissions, user ID, link count, etc, only affects the inode!
• ctime is modified automatically! (stat, access)
• Example: reading/writing a file only affects the file, instead of the residing dir (Fig4.13).
46
#include <sys/types.h>
#include <utime.h> struct utimbuf { time_t actime;
} time_t modtime;
– time values are in seconds since the Epoch
– times = null set as the current time
• Effective UID = file UID or W right to the file
– times != null set as requested
• Effective UID = (file UID or superuser) and W right to the file.
– Program 4.21
47
#include "apue.h"
#include <fcntl.h>
#include <utime.h>
}
{
Int main(int argc, char *argv[]) int struct stat struct utimbuf timebuf; statbuf; i, fd; for (i = 1; i < argc; i++) { if (stat(argv[i], &statbuf) < 0) { current times */
/* fetch err_ret("%s: stat error", argv[i]); continue;
} if ((fd = open(argv[i], O_RDWR | O_TRUNC))
< 0) { /* truncate */ err_ret("%s: open error", argv[i]); continue;
} close(fd); timebuf.actime = statbuf.st_atime;
} timebuf.modtime = statbuf.st_mtime; if (utime(argv[i], &timebuf) < 0) {
/* reset times */ err_ret("%s: utime error", argv[i]); continue;
} exit(0);
• Change: atime, mtime, ctime?
> ls -l changemod
-rw-r--r-- 1 hchu professor 0 Apr 12 00:35 changemod
> ls -lu changemod
-rw-r--r-- 1 hchu professor 0 Apr 12 00:36 changemod
> date
Wed Apr 12 00:40:55 CST 2006
> ./fig4.21.exe changemod
> ls -l changemod
-rw-r--r-- 1 hchu professor 0 Apr 12 00:35 changemod
> ls -lu changemod
-rw-r--r-- 1 hchu professor 0 Apr 12 00:36 changemod
> ls -lc changemod
-rw-r--r-- 1 hchu professor 0 Apr 12 00:41 changemod
48
#include <sys/types.h>
#include <sys/stat.h>
– umask, UID/GID setup (Sec 4.6)
– From 4.2BSD & SVR3 (SVR4 – inheritance of the S_ISGID bit)
#include <unistd.h>
– An empty dir is deleted.
– Link count reaches zero, and no one still opens the dir.
49
#include <sys/types.h>
#include <dirent.h>
– Only the kernel can write to a dir!!!
– WX for creating/deleting a file!
– Implementation-dependent!
50
struct dirent { ino_t d_ino; /* not in POSIX.1 */ char d_name[NAME_MAX+1];
} /* fpathconf() */
51
#include "apue.h"
#include <dirent.h>
#include <limits.h>
/* function type that is called for each filename */ typedef int struct stat *, int);
Myfunc(const char *, const static Myfunc myfunc; static int static int myftw(char *, Myfunc *); dopath(Myfunc *); static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;
{ int main(int argc, char *argv[]) int ret; if (argc != 2) err_quit("usage: ftw <starting-pathname>"); ret = myftw(argv[1], myfunc); does it all */
/* ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock; if (ntot == 0) ntot = 1;
0; print 0 for all counts */
/* avoid divide by printf("regular files = %7ld, %5.2f %%\n", nreg, nreg*100.0/ntot); printf("directories = %7ld, %5.2f %%\n", ndir, ndir*100.0/ntot); printf("block special = %7ld, %5.2f
%%\n", nblk, nblk*100.0/ntot); printf("char special = %7ld, %5.2f
%%\n", nchr, nchr*100.0/ntot); printf("FIFOs = %7ld, %5.2f
%%\n", nfifo, nfifo*100.0/ntot); printf("symbolic links = %7ld, %5.2f
%%\n", nslink, nslink*100.0/ntot); printf("sockets = %7ld, %5.2f
%%\n", nsock, nsock*100.0/ntot);
} exit(ret);
52
/*
* Descend through the hierarchy, starting at "pathname".
* The caller's func() is called for every file.
*/
#define FTW_F 1 file other than directory */
#define FTW_D directory */
2
#define FTW_DNR 3 directory that can't be read */
#define FTW_NS file that we can't stat */
4
/*
/*
/*
/* static char *fullpath; pathname for every file */
/* contains full
}
{ static int
/* we return whatever func() returns */ myftw(char *pathname, Myfunc *func) int len; fullpath = path_alloc(&len);
PATH_MAX+1 bytes */
/* malloc's for
({Prog pathalloc}) */ strncpy(fullpath, pathname, len);
*/ fullpath[len-1] = 0;
/* buffer overrun */
/*
/* protect against return(dopath(func));
53
/*
* Descend through the hierarchy, starting at "fullpath".
* If "fullpath" is anything other than a directory, we lstat() it,
* call func(), and return. For a directory, we call ourself
* recursively for each name in the directory.
{
*/ static int
/* we return whatever func() returns */ dopath(Myfunc* func) struct stat struct dirent *dirp; statbuf;
DIR
*dp; int char *ptr; ret; if (lstat(fullpath, &statbuf) < 0) /* stat error */ return(func(fullpath, &statbuf, FTW_NS)); if (S_ISDIR(statbuf.st_mode) == 0) /* not a directory
*/ return(func(fullpath, &statbuf, FTW_F));
/*
* It's a directory. First call func() for the directory,
* then process each filename in the directory.
*/ if ((ret = func(fullpath, &statbuf, FTW_D)) != 0) return(ret);
} ptr = fullpath + strlen(fullpath); /* point to end of fullpath */
*ptr++ = '/';
*ptr = 0; if ((dp = opendir(fullpath)) == NULL) can't read directory */ return(func(fullpath, &statbuf,
FTW_DNR));
/* while ((dirp = readdir(dp)) != NULL) { if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) continue;
/* ignore dot and dot-dot */ strcpy(ptr, dirp->d_name); append name after slash */
/* if ((ret = dopath(func)) != 0)
/* recursive */ break; /* time to leave
}
*/ ptr[-1] = 0; slash onwards */
/* erase everything from if (closedir(dp) < 0) fullpath); err_ret("can't close directory %s", return(ret);
54
{ static int myfunc(const char *pathname, const struct stat
*statptr, int type) switch (type) { case FTW_F: switch (statptr->st_mode & S_IFMT) { case S_IFREG: break; nreg++; nblk++; case S_IFBLK: break; case S_IFCHR: break; nchr++; nfifo++; case S_IFIFO: break; case S_IFLNK: break; case S_IFSOCK: break; nslink++; nsock++; case S_IFDIR: err_dump("for S_IFDIR for
%s",
} pathname); directories should have type = FTW_D */
} break; case FTW_D: ndir++; break; case FTW_DNR: err_ret("can't read directory %s", pathname); break; case FTW_NS: err_ret("stat error for %s", pathname); break;
/*
} default: err_dump("unknown type %d for pathname %s", type, pathname); return(0);
55
#include <unistd.h> int chdir(const char *pathname); int fchdir(int filedes);
– Every process has its own current working directory
– Per-process attribute – working dir!
– chdir must be built into shells (pwd)!
– The kernel only maintains the i-node number and dev ID for the current working directory!
• Program 4.23
56
#include "apue.h"
}
{ int main(void) if (chdir("/tmp") < 0) err_sys("chdir failed"); printf("chdir to /tmp succeeded\n"); exit(0);
> pwd
?
/usr/lib
> mycd
>chdir to /tmp succeeded
> pwd
57
#include <unistd.h>
– The buffer must be large enough, or an error returns!
– chdir follows symbolic links, and getcwd has not idea of symbolic links!
– getcwd
58
• Device Number – dev_t
– Major and minor numbers: 8 bit each under 4.3+BSD
– macro definition <sysmacros.h> @ntucsa
#define L_BITSMINOR 18 /* # of SVR4 minor device bits */
#define L_MAXMAJ 0x3fff /* SVR4 max major value */
#define major(x) (int)((unsigned)((x)>>O_BITSMINOR) & O_MAXMAJ)
• Program 4.25
– st_dev vs st_rdev
59
Driver
Controller 1
Major #1
USB Controller
Controller 2
Major #2
Controller 3
Major #3
Device 1
Minor #1
USB KB
Device 2
Minor #2
USB Cam
Device 1
Minor #1
Device 2
Minor #2
Device 1
Minor #1
Device 2
Minor #2
60
}
#include "apue.h"
#ifdef SOLARIS
#include <sys/mkdev.h>
#endif
{ int main(int argc, char *argv[]) int struct stat buf; i; for (i = 1; i < argc; i++) { printf("%s: ", argv[i]);
} if (stat(argv[i], &buf) < 0) { err_ret("stat error"); continue;
} exit(0); printf("dev = %d/%d", major(buf.st_dev), minor(buf.st_dev)); if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) { printf(" (%s) rdev = %d/%d",
(S_ISCHR(buf.st_mode)) ? "character" : "block", major(buf.st_rdev), minor(buf.st_rdev));
} printf("\n");
61