|
CITS2002 Systems Programming |
CITS2002 |
CITS2002 schedule |
|||||
System-calls and system-defined structuresMost system-calls accept integers and pointers to characters as parameters, and typically return integer values indicating their success. When more information must be passed to a system-call, or the call needs to return multiple values, we employ system-defined (C11) structures defined in operating system provided header files.Accessing structures using pointersWe've seen that we can access fields of a structure using a single dot ('.' or fullstop).What if, instead of accessing the structure directly, we only have a pointer to a structure? We've seen "one side" of this situation, already - when we passed the address of a structure to a function:
struct timeval start_time;
gettimeofday( &start_time, NULL );
The function gettimeofday(), must have been declared to receive a pointer:
extern int gettimeofday( struct timeval *time, ......);
Consider the following example,
in which a pointer to a structure
is returned from a function.
We now use the → operator (pronounced the 'arrow', or 'points-to' operator) to access the fields via the pointer:
CITS2002 Systems Programming, Lecture 16, p1, 19th September 2023.
Another example - accessing a system's password entriesOn a stand-alone Linux system, one not dependent on a network-based server to provide its user information, some local user information is (historically) stored in the textfile /etc/passwd, with each user's information stored one-per-line with fields separated by colons.Rather than expecting every user program to parse this information correctly, Linux systems host standard XOPEN header files and libraries to conveniently provide the information. We can iterate through this information with the help of the getpwent() function, which returns a pointer to a 'struct passwd' structure:
CITS2002 Systems Programming, Lecture 16, p2, 19th September 2023.
Defining our own datatypesWe can further simplify our code, and more clearly identify related data by defining our own datatypes.Recall material from Lecture-6 where structures, and arrays of structures were introduced. We preceded each structure's name with the struct keyword, and accessed structure elements using the 'dot' operator. Instead, we can use the typedef keyword to define our own new datatype in terms of an old (existing) datatype, and then not have to always provide the struct keyword:
As a convention (but not a C11 requirement), we'll define our user-defined types using uppercase names:
CITS2002 Systems Programming, Lecture 16, p3, 19th September 2023.
Defining our own datatypes, continuedLet's consider another example - the starting (home) and ending (destination) bustops from the CITS2002 1st project of 2015.We starting with some of its definitions:
CITS2002 Systems Programming, Lecture 16, p4, 19th September 2023.
Finding the attributes of a fileAs seen in Lecture-15, many operating systems manage their data in a file system, in particular maintaining files in a hierarchical directory structure - directories contain files and other (sub)directories.As we saw with time-based information, we may request file- and directory information from the operating system by calling system-calls. We may employ another POSIX† function, stat(), and the system-provided structure struct stat, to determine the attributes of each file:
†POSIX
is an acronym for "Portable Operating System Interface", a family of
standards specified by the IEEE for maintaining compatibility between
operating systems.
POSIX defines the application programming interface
(API), along with command line shells and utility interfaces, for software
compatibility with variants of Unix (such as macOS and Linux)
and other operating systems (e.g. Windows has a POSIX emulation layer).
CITS2002 Systems Programming, Lecture 16, p5, 19th September 2023.
Reading the contents of a directoryMost modern operating systems store their data in hierarchical file systems, consisting of directories which hold items that, themselves, may either be files or directories.The formats used to store information in directories in different file-systems are different(!), and so when writing portable C programs, we prefer to use functions that work portably. Consider the strong similarities between opening and reading a (text) file, and opening and reading a directory:
With directories, we're again discussing functions that are not part of the C11 standard, but are defined by POSIX standards. The inconsistent naming of system-defined datatypes - for example, struct dirent versus DIR - can be confusing (annoying) but, over time, renaming datatypes across billions of lines of open-source code becomes impossible.
CITS2002 Systems Programming, Lecture 16, p6, 19th September 2023.
Investigating the contents of a directoryWe now know how to open a directory for reading, and to determine the names of all items in that directory. What is each "thing" found in the directory - is it a directory, is it a file...? To answer those questions, we need to employ the POSIX function, stat(), to determine the attributes of the items we find in directories:
CITS2002 Systems Programming, Lecture 16, p7, 19th September 2023.
File and Directory PermissionsRecall that:
From history,
the permission mode bits appear in the same integer defining
the file's type (regular, directory, block device, socket, ...) -
See man 2 stat for details.
CITS2002 Systems Programming, Lecture 16, p8, 19th September 2023.
File and Directory Permissions, continuedWhen access requests are made by a process on behalf of a subject (a user) for an object (a file), the Unix kernel compares the effective user- and group-id attributes of the process against the permission mode bits of the file. Of note, if the owner's permission bits of a file or directory are not set, then the owner cannot access the object by virtue of the 'group' or 'other' bits (can you think why?). The inode structure also contains indication of the object's setuid and setgid status, together with a sticky bit having an overloaded meaning (historically, setting the sticky bit on an executable file requested that it not be swapped out of memory - requiring privilege to set the bit). On different variants of Unix/Linux the permission mode bits, in combination, have some obscure meanings:
CITS2002 Systems Programming, Lecture 16, p9, 19th September 2023.
Describing permissions using octal valuesWhile we know that all data within a computer is stored in binary, we do not refer to or describe system-focused values with ones-and-zeroes.In the case of file-system permissions, 3 bits (ranging over the integer values 0..7) are used to store Boolean values for the read, write, and execute permissions. Further, 3 sets of these 3 permissions bits, one for each of the user, group, and 'other' owners are employed for each file-system entry. So, while we don't describe these data values in binary, it makes a lot of sense to describe them using octal values:
CITS2002 Systems Programming, Lecture 16, p10, 19th September 2023.
Accessing file-system permission bitsThe previous examples, using RGB colour values, only employed individual bytes of the integers being considered.Here we need to access individual bits, using each bit as if it were a Boolean value (which C11 doesn't directly support). Recall that we have seen how we can determine if a directory entry is another directory or a file:
This C program better explains demonstrates these concepts: showmode.c
CITS2002 Systems Programming, Lecture 16, p11, 19th September 2023.
|