class: center, middle # Environment Variables ## Alan Cox and Scott Rixner --- layout: true --- # Process Environment Every process has an environment described by a set of environment variables: ```shell $ printenv SHELL=/bin/bash HOSTNAME=agate.clear9.rice.edu PWD=/storage-home/r/rixner XDG_SESSION_TYPE=tty MANPATH=/usr/share/man: HOME=/storage-home/r/rixner LANG=en_US.UTF-8 USER=rixner PATH=/storage-home/r/rixner/.local/bin:/storage-home/r/rixner/bin:/usr/share/Modules/bin:/usr/lib64/ccache:/usr/local/ bin:/usr/bin:/usr/local/sbin:/usr/sbin ... ``` --- # Environment Variables Programs use environment variables to customize their behavior .mb-0[ Examples: ] - `LANG` - Specifies the language and localization settings - `en_US.UTF-8` indicates UTF-8 encoding of English language - Programs should display and format messages in this language - `PWD` - Current working directory --- # PATH Environment Variable - Specifies the directories to search for executable programs - Colon separated list of directories Example path: "`/storage-home/r/rixner/.local/bin:/storage-home/r/rixner/bin:/usr/local/bin:/usr/bin`" .mb-0[ Directories in that path: ] - `/storage-home/r/rixner/.local/bin` - `/storage-home/r/rixner/bin` - `/usr/local/bin` - `/usr/bin` --- # Running a Program (Simplified) - The user types a command - The shell retrieves the path and splits it into directories - Split path on ":" character - For each directory (in order), the shell: - Creates full file path by concatenating the directory and the command name (with a "/" in between) - Requests that the kernel execute the file - If the request fails, continue - If executable not found, the shell prints an error message --- # Today's Exercise: Which - Write a program that mimics the (simplified) behavior of the `which(1)` command - Given a command name, print the full path to the executable - Also print whether `user`, `group`, and/or `other` may execute the file .mb-0[ Example: ] ```shell $ ./mywhich ls /usr/bin/ls (user group other) ``` --- # Skeleton - Retrieve PATH and split it into directories - For each directory (in order): - Concatenate directory with "/" and command line argument - Check if the resulting file exists and is executable - If executable found, print the full path, executable permissions, and exit - If executable not found, print an error message If there is an empty directory in the path, check for the executable in the current directory --- # Useful Functions - `getenv(3)` - Get the value of an environment variable - `stat(2)` - Get file status information - `strcat(3)`, `strdup(3)`, `strlen(3)`, and `strsep(3)` - String operations - `perror(3)` - Print an error message based on `errno` --- # `stat(2)` .mb-0[ Return metadata about a file: ] ``` struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* Inode number */ mode_t st_mode; /* File type and mode */ nlink_t st_nlink; /* Number of hard links */ uid_t st_uid; /* User ID of owner */ gid_t st_gid; /* Group ID of owner */ dev_t st_rdev; /* Device ID (if special file) */ off_t st_size; /* Total size, in bytes */ blksize_t st_blksize; /* Block size for filesystem I/O */ blkcnt_t st_blocks; /* Number of 512 B blocks allocated */ struct timespec st_atim; /* Time of last access */ struct timespec st_mtim; /* Time of last modification */ struct timespec st_ctim; /* Time of last status change */ }; ``` --- # File Mode - `st_mode` - File protection and type - Relevant mode values (defined in `sys/stat.h`) - `S_IXUSR` - User has execute permission - `S_IXGRP` - Group has execute permisson - `S_IXOTH` - Other users have execute permission --- # `strsep(3)` - Replaces the next delimiter in the string with a null terminator - Sets the pointer to point to the character after the delimiter - Returns the the original pointer argument - Read the `man` page carefully! --- class: center, middle # Get Started!