diff options
author | tcsullivan <tullivan99@gmail.com> | 2018-11-17 13:02:57 -0500 |
---|---|---|
committer | tcsullivan <tullivan99@gmail.com> | 2018-11-17 13:02:57 -0500 |
commit | c6ef89664b8c0d7aa85bddd5c7014aa6df82cbe7 (patch) | |
tree | d1f9d09412a46bdf4344fe30392455070a72993d /src/sash/utils.c | |
parent | db38c4b9dac461de0ed75bf6d079dacba1b31bc9 (diff) |
added pdclib, removed sash
Diffstat (limited to 'src/sash/utils.c')
-rw-r--r-- | src/sash/utils.c | 1144 |
1 files changed, 0 insertions, 1144 deletions
diff --git a/src/sash/utils.c b/src/sash/utils.c deleted file mode 100644 index f6bee83..0000000 --- a/src/sash/utils.c +++ /dev/null @@ -1,1144 +0,0 @@ -/* - * Copyright (c) 2014 by David I. Bell - * Permission is granted to use, distribute, or modify this source, - * provided that this copyright notice remains intact. - * - * Utility routines. - */ - -#include "sash.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include "dirent.h" -#include <utime.h> - - -/* - * A chunk of data. - * Chunks contain data which is allocated as needed, but which is - * not freed until all of the data needs freeing, such as at - * the beginning of the next command. - */ -typedef struct chunk CHUNK; -#define CHUNK_INIT_SIZE 4 - -struct chunk -{ - CHUNK * next; - char data[CHUNK_INIT_SIZE]; /* actually of varying length */ -}; - - -static CHUNK * chunkList; - - - -/* - * Return the standard ls-like mode string from a file mode. - * This is static and so is overwritten on each call. - */ -const char * -modeString(int mode) -{ - static char buf[12]; - - strcpy(buf, "----------"); - - /* - * Fill in the file type. - */ - if (S_ISDIR(mode)) - buf[0] = 'd'; - if (S_ISCHR(mode)) - buf[0] = 'c'; - if (S_ISBLK(mode)) - buf[0] = 'b'; - if (S_ISFIFO(mode)) - buf[0] = 'p'; -#ifdef S_ISLNK - if (S_ISLNK(mode)) - buf[0] = 'l'; -#endif -#ifdef S_ISSOCK - if (S_ISSOCK(mode)) - buf[0] = 's'; -#endif - - /* - * Now fill in the normal file permissions. - */ - if (mode & S_IRUSR) - buf[1] = 'r'; - if (mode & S_IWUSR) - buf[2] = 'w'; - if (mode & S_IXUSR) - buf[3] = 'x'; - if (mode & S_IRGRP) - buf[4] = 'r'; - if (mode & S_IWGRP) - buf[5] = 'w'; - if (mode & S_IXGRP) - buf[6] = 'x'; - if (mode & S_IROTH) - buf[7] = 'r'; - if (mode & S_IWOTH) - buf[8] = 'w'; - if (mode & S_IXOTH) - buf[9] = 'x'; - - /* - * Finally fill in magic stuff like suid and sticky text. - */ - if (mode & S_ISUID) - buf[3] = ((mode & S_IXUSR) ? 's' : 'S'); - if (mode & S_ISGID) - buf[6] = ((mode & S_IXGRP) ? 's' : 'S'); - if (mode & S_ISVTX) - buf[9] = ((mode & S_IXOTH) ? 't' : 'T'); - - return buf; -} - - -/* - * Get the time string to be used for a file. - * This is down to the minute for new files, but only the date for old files. - * The string is returned from a static buffer, and so is overwritten for - * each call. - */ -const char * -timeString(time_t timeVal) -{ - time_t now; - char * str; - static char buf[26]; - - time(&now); - - str = ctime(&timeVal); - - strcpy(buf, &str[4]); - buf[12] = '\0'; - - if ((timeVal > now) || (timeVal < now - 365*24*60*60L)) - { - strcpy(&buf[7], &str[20]); - buf[11] = '\0'; - } - - return buf; -} - - -/* - * Return TRUE if a fileName is a directory. - * Nonexistant files return FALSE. - */ -BOOL -isDirectory(const char * name) -{ - struct stat statBuf; - - if (stat(name, &statBuf) < 0) - return FALSE; - - return S_ISDIR(statBuf.st_mode); -} - - -/* - * Return TRUE if a filename is a block or character device. - * Nonexistant files return FALSE. - */ -BOOL -isDevice(const char * name) -{ - struct stat statBuf; - - if (stat(name, &statBuf) < 0) - return FALSE; - - return S_ISBLK(statBuf.st_mode) || S_ISCHR(statBuf.st_mode); -} - - -/* - * Copy one file to another, while possibly preserving its modes, times, - * and modes. Returns TRUE if successful, or FALSE on a failure with an - * error message output. (Failure is not indicted if the attributes cannot - * be set.) - */ -BOOL -copyFile( - const char * srcName, - const char * destName, - BOOL setModes -) -{ - int rfd; - int wfd; - int rcc; - char buf[BUF_SIZE]; - struct stat statBuf1; - struct stat statBuf2; - struct utimbuf times; - - if (stat(srcName, &statBuf1) < 0) - { - perror(srcName); - - return FALSE; - } - - if (stat(destName, &statBuf2) < 0) - { - statBuf2.st_ino = -1; - statBuf2.st_dev = -1; - } - - if ((statBuf1.st_dev == statBuf2.st_dev) && - (statBuf1.st_ino == statBuf2.st_ino)) - { - fprintf(stderr, "Copying file \"%s\" to itself\n", srcName); - - return FALSE; - } - - rfd = open(srcName, O_RDONLY); - - if (rfd < 0) - { - perror(srcName); - - return FALSE; - } - - wfd = creat(destName, statBuf1.st_mode); - - if (wfd < 0) - { - perror(destName); - close(rfd); - - return FALSE; - } - - while ((rcc = read(rfd, buf, sizeof(buf))) > 0) - { - if (intFlag) - { - close(rfd); - close(wfd); - - return FALSE; - } - - if (fullWrite(wfd, buf, rcc) < 0) - goto error_exit; - } - - if (rcc < 0) - { - perror(srcName); - goto error_exit; - } - - checkStatus("close", close(rfd)); - - if (close(wfd) < 0) - { - perror(destName); - - return FALSE; - } - - if (setModes) - { - checkStatus("chmod", chmod(destName, statBuf1.st_mode)); - - checkStatus("chown", chown(destName, statBuf1.st_uid, statBuf1.st_gid)); - - times.actime = statBuf1.st_atime; - times.modtime = statBuf1.st_mtime; - - checkStatus("utime", utime(destName, ×)); - } - - return TRUE; - - -error_exit: - close(rfd); - close(wfd); - - return FALSE; -} - - -/* - * Build a path name from the specified directory name and file name. - * If the directory name is NULL, then the original fileName is returned. - * The built path is in a static area, and is overwritten for each call. - */ -const char * -buildName(const char * dirName, const char * fileName) -{ - const char * cp; - static char buf[PATH_LEN]; - - if ((dirName == NULL) || (*dirName == '\0')) - return fileName; - - cp = strrchr(fileName, '/'); - - if (cp) - fileName = cp + 1; - - strcpy(buf, dirName); - strcat(buf, "/"); - strcat(buf, fileName); - - return buf; -} - - -/* - * Expand the wildcards in a fileName wildcard pattern, if any. - * Returns an argument list with matching fileNames in sorted order. - * The expanded names are stored in memory chunks which can later all - * be freed at once. The returned list is only valid until the next - * call or until the next command. Returns zero if the name is not a - * wildcard, or returns the count of matched files if the name is a - * wildcard and there was at least one match, or returns -1 if either - * no fileNames matched or there was an allocation error. - */ -int -expandWildCards(const char * fileNamePattern, const char *** retFileTable) -{ - const char * last; - const char * cp1; - const char * cp2; - const char * cp3; - char * str; - DIR * dirp; - struct dirent * dp; - int dirLen; - int newFileTableSize; - char ** newFileTable; - char dirName[PATH_LEN]; - - static int fileCount; - static int fileTableSize; - static char ** fileTable; - - /* - * Clear the return values until we know their final values. - */ - fileCount = 0; - *retFileTable = NULL; - - /* - * Scan the file name pattern for any wildcard characters. - */ - cp1 = strchr(fileNamePattern, '*'); - cp2 = strchr(fileNamePattern, '?'); - cp3 = strchr(fileNamePattern, '['); - - /* - * If there are no wildcard characters then return zero to - * indicate that there was actually no wildcard pattern. - */ - if ((cp1 == NULL) && (cp2 == NULL) && (cp3 == NULL)) - return 0; - - /* - * There are wildcards in the specified filename. - * Get the last component of the file name. - */ - last = strrchr(fileNamePattern, '/'); - - if (last) - last++; - else - last = fileNamePattern; - - /* - * If any wildcards were found before the last filename component - * then return an error. - */ - if ((cp1 && (cp1 < last)) || (cp2 && (cp2 < last)) || - (cp3 && (cp3 < last))) - { - fprintf(stderr, - "Wildcards only implemented for last file name component\n"); - - return -1; - } - - /* - * Assume at first that we are scanning the current directory. - */ - dirName[0] = '.'; - dirName[1] = '\0'; - - /* - * If there was a directory given as part of the file name then - * copy it and null terminate it. - */ - if (last != fileNamePattern) - { - memcpy(dirName, fileNamePattern, last - fileNamePattern); - dirName[last - fileNamePattern - 1] = '\0'; - - if (dirName[0] == '\0') - { - dirName[0] = '/'; - dirName[1] = '\0'; - } - } - - /* - * Open the directory containing the files to be checked. - */ - dirp = opendir(dirName); - - if (dirp == NULL) - { - perror(dirName); - - return -1; - } - - /* - * Prepare the directory name for use in making full path names. - */ - dirLen = strlen(dirName); - - if (last == fileNamePattern) - { - dirLen = 0; - dirName[0] = '\0'; - } - else if (dirName[dirLen - 1] != '/') - { - dirName[dirLen++] = '/'; - dirName[dirLen] = '\0'; - } - - /* - * Find all of the files in the directory and check them against - * the wildcard pattern. - */ - while ((dp = readdir(dirp)) != NULL) - { - /* - * Skip the current and parent directories. - */ - if ((strcmp(dp->d_name, ".") == 0) || - (strcmp(dp->d_name, "..") == 0)) - { - continue; - } - - /* - * If the file name doesn't match the pattern then skip it. - */ - if (!match(dp->d_name, last)) - continue; - - /* - * This file name is selected. - * See if we need to reallocate the file name table. - */ - if (fileCount >= fileTableSize) - { - /* - * Increment the file table size and reallocate it. - */ - newFileTableSize = fileTableSize + EXPAND_ALLOC; - - newFileTable = (char **) realloc((char *) fileTable, - (newFileTableSize * sizeof(char *))); - - if (newFileTable == NULL) - { - fprintf(stderr, "Cannot allocate file list\n"); - closedir(dirp); - - return -1; - } - - fileTable = newFileTable; - fileTableSize = newFileTableSize; - } - - /* - * Allocate space for storing the file name in a chunk. - */ - str = getChunk(dirLen + strlen(dp->d_name) + 1); - - if (str == NULL) - { - fprintf(stderr, "No memory for file name\n"); - closedir(dirp); - - return -1; - } - - /* - * Save the file name in the chunk. - */ - if (dirLen) - memcpy(str, dirName, dirLen); - - strcpy(str + dirLen, dp->d_name); - - /* - * Save the allocated file name into the file table. - */ - fileTable[fileCount++] = str; - } - - /* - * Close the directory and check for any matches. - */ - closedir(dirp); - - if (fileCount == 0) - { - fprintf(stderr, "No matches\n"); - - return -1; - } - - /* - * Sort the list of file names. - */ - qsort((void *) fileTable, fileCount, sizeof(char *), nameSort); - - /* - * Return the file list and count. - */ - *retFileTable = (const char **) fileTable; - - return fileCount; -} - - -/* - * Sort routine for list of fileNames. - */ -int -nameSort(const void * p1, const void * p2) -{ - const char ** s1; - const char ** s2; - - s1 = (const char **) p1; - s2 = (const char **) p2; - - return strcmp(*s1, *s2); -} - - -/* - * Routine to see if a text string is matched by a wildcard pattern. - * Returns TRUE if the text is matched, or FALSE if it is not matched - * or if the pattern is invalid. - * * matches zero or more characters - * ? matches a single character - * [abc] matches 'a', 'b' or 'c' - * \c quotes character c - * Adapted from code written by Ingo Wilken. - */ -BOOL -match(const char * text, const char * pattern) -{ - const char * retryPat; - const char * retryText; - int ch; - BOOL found; - - retryPat = NULL; - retryText = NULL; - - while (*text || *pattern) - { - ch = *pattern++; - - switch (ch) - { - case '*': - retryPat = pattern; - retryText = text; - break; - - case '[': - found = FALSE; - - while ((ch = *pattern++) != ']') - { - if (ch == '\\') - ch = *pattern++; - - if (ch == '\0') - return FALSE; - - if (*text == ch) - found = TRUE; - } - - if (!found) - { - pattern = retryPat; - text = ++retryText; - } - - /* fall into next case */ - - case '?': - if (*text++ == '\0') - return FALSE; - - break; - - case '\\': - ch = *pattern++; - - if (ch == '\0') - return FALSE; - - /* fall into next case */ - - default: - if (*text == ch) - { - if (*text) - text++; - break; - } - - if (*text) - { - pattern = retryPat; - text = ++retryText; - break; - } - - return FALSE; - } - - if (pattern == NULL) - return FALSE; - } - - return TRUE; -} - - -/* - * Take a command string and break it up into an argc, argv list while - * handling quoting and wildcards. The returned argument list and - * strings are in static memory, and so are overwritten on each call. - * The argument list is ended with a NULL pointer for convenience. - * Returns TRUE if successful, or FALSE on an error with a message - * already output. - */ -BOOL -makeArgs(const char * cmd, int * retArgc, const char *** retArgv) -{ - const char * argument; - char * cp; - char * cpOut; - char * newStrings; - const char ** fileTable; - const char ** newArgTable; - int newArgTableSize; - int fileCount; - int len; - int ch; - int quote; - BOOL quotedWildCards; - BOOL unquotedWildCards; - - static int stringsLength; - static char * strings; - static int argCount; - static int argTableSize; - static const char ** argTable; - - /* - * Clear the returned values until we know them. - */ - argCount = 0; - *retArgc = 0; - *retArgv = NULL; - - /* - * Copy the command string into a buffer that we can modify, - * reallocating it if necessary. - */ - len = strlen(cmd) + 1; - - if (len > stringsLength) - { - newStrings = realloc(strings, len); - - if (newStrings == NULL) - { - fprintf(stderr, "Cannot allocate string\n"); - - return FALSE; - } - - strings = newStrings; - stringsLength = len; - } - - memcpy(strings, cmd, len); - cp = strings; - - /* - * Keep parsing the command string as long as there are any - * arguments left. - */ - while (*cp) - { - /* - * Save the beginning of this argument. - */ - argument = cp; - cpOut = cp; - - /* - * Reset quoting and wildcarding for this argument. - */ - quote = '\0'; - quotedWildCards = FALSE; - unquotedWildCards = FALSE; - - /* - * Loop over the string collecting the next argument while - * looking for quoted strings or quoted characters, and - * remembering whether there are any wildcard characters - * in the argument. - */ - while (*cp) - { - ch = *cp++; - - /* - * If we are not in a quote and we see a blank then - * this argument is done. - */ - if (isBlank(ch) && (quote == '\0')) - break; - - /* - * If we see a backslash then accept the next - * character no matter what it is. - */ - if (ch == '\\') - { - ch = *cp++; - - /* - * Make sure there is a next character. - */ - if (ch == '\0') - { - fprintf(stderr, - "Bad quoted character\n"); - - return FALSE; - } - - /* - * Remember whether the quoted character - * is a wildcard. - */ - if (isWildCard(ch)) - quotedWildCards = TRUE; - - *cpOut++ = ch; - - continue; - } - - /* - * If we see one of the wildcard characters then - * remember whether it was seen inside or outside - * of quotes. - */ - if (isWildCard(ch)) - { - if (quote) - quotedWildCards = TRUE; - else - unquotedWildCards = TRUE; - } - - /* - * If we were in a quote and we saw the same quote - * character again then the quote is done. - */ - if (ch == quote) - { - quote = '\0'; - - continue; - } - - /* - * If we weren't in a quote and we see either type - * of quote character, then remember that we are - * now inside of a quote. - */ - if ((quote == '\0') && ((ch == '\'') || (ch == '"'))) - { - quote = ch; - - continue; - } - - /* - * Store the character. - */ - *cpOut++ = ch; - } - - /* - * Make sure that quoting is terminated properly. - */ - if (quote) - { - fprintf(stderr, "Unmatched quote character\n"); - - return FALSE; - } - - /* - * Null terminate the argument if it had shrunk, and then - * skip over all blanks to the next argument, nulling them - * out too. - */ - if (cp != cpOut) - *cpOut = '\0'; - - while (isBlank(*cp)) - *cp++ = '\0'; - - /* - * If both quoted and unquoted wildcards were used then - * complain since we don't handle them properly. - */ - if (quotedWildCards && unquotedWildCards) - { - fprintf(stderr, - "Cannot use quoted and unquoted wildcards\n"); - - return FALSE; - } - - /* - * Expand the argument into the matching filenames or accept - * it as is depending on whether there were any unquoted - * wildcard characters in it. - */ - if (unquotedWildCards) - { - /* - * Expand the argument into the matching filenames. - */ - fileCount = expandWildCards(argument, &fileTable); - - /* - * Return an error if the wildcards failed to match. - */ - if (fileCount < 0) - return FALSE; - - if (fileCount == 0) - { - fprintf(stderr, "Wildcard expansion error\n"); - - return FALSE; - } - } - else - { - /* - * Set up to only store the argument itself. - */ - fileTable = &argument; - fileCount = 1; - } - - /* - * Now reallocate the argument table to hold the file name. - */ - if (argCount + fileCount >= argTableSize) - { - newArgTableSize = argCount + fileCount + 1; - - newArgTable = (const char **) realloc(argTable, - (sizeof(const char *) * newArgTableSize)); - - if (newArgTable == NULL) - { - fprintf(stderr, "No memory for arg list\n"); - - return FALSE; - } - - argTable = newArgTable; - argTableSize = newArgTableSize; - } - - /* - * Copy the new arguments to the end of the old ones. - */ - memcpy((void *) &argTable[argCount], (const void *) fileTable, - (sizeof(const char **) * fileCount)); - - /* - * Add to the argument count. - */ - argCount += fileCount; - } - - /* - * Null terminate the argument list and return it. - */ - argTable[argCount] = NULL; - - *retArgc = argCount; - *retArgv = argTable; - - return TRUE; -} - - -/* - * Make a NULL-terminated string out of an argc, argv pair. - * Returns TRUE if successful, or FALSE if the string is too long, - * with an error message given. This does not handle spaces within - * arguments correctly. - */ -BOOL -makeString( - int argc, - const char ** argv, - char * buf, - int bufLen -) -{ - int len; - - while (argc-- > 0) - { - len = strlen(*argv); - - if (len >= bufLen) - { - fprintf(stderr, "Argument string too long\n"); - - return FALSE; - } - - strcpy(buf, *argv++); - - buf += len; - bufLen -= len; - - if (argc) - *buf++ = ' '; - - bufLen--; - } - - *buf = '\0'; - - return TRUE; -} - - -/* - * Allocate a chunk of memory (like malloc). - * The difference, though, is that the memory allocated is put on a - * list of chunks which can be freed all at one time. You CAN NOT free - * an individual chunk. - */ -char * -getChunk(int size) -{ - CHUNK * chunk; - - if (size < CHUNK_INIT_SIZE) - size = CHUNK_INIT_SIZE; - - chunk = (CHUNK *) malloc(size + sizeof(CHUNK) - CHUNK_INIT_SIZE); - - if (chunk == NULL) - return NULL; - - chunk->next = chunkList; - chunkList = chunk; - - return chunk->data; -} - - -/* - * Duplicate a string value using the chunk allocator. - * The returned string cannot be individually freed, but can only be freed - * with other strings when freeChunks is called. Returns NULL on failure. - */ -char * -chunkstrdup(const char * str) -{ - int len; - char * newStr; - - len = strlen(str) + 1; - newStr = getChunk(len); - - if (newStr) - memcpy(newStr, str, len); - - return newStr; -} - - -/* - * Free all chunks of memory that had been allocated since the last - * call to this routine. - */ -void -freeChunks(void) -{ - CHUNK * chunk; - - while (chunkList) - { - chunk = chunkList; - chunkList = chunk->next; - free((char *) chunk); - } -} - - -/* - * Try writing data to the specified file descriptor. - * Only the first write error if any is printed. - * This is used when writing to STDOUT. - */ -void -tryWrite(int fd, const char * cp, int len) -{ - static int failed = FALSE; - - int status = fullWrite(fd, cp, len); - - if ((status < 0) && !failed) - { - failed = TRUE; - perror("write"); - } -} - - -/* - * Write all of the supplied buffer out to a file. - * This does multiple writes as necessary. - * Returns the amount written, or -1 on an error. - */ -int -fullWrite(int fd, const char * buf, int len) -{ - int cc; - int total; - - total = 0; - - while (len > 0) - { - cc = write(fd, buf, len); - - if (cc < 0) - return -1; - - buf += cc; - total+= cc; - len -= cc; - } - - return total; -} - - -/* - * Read all of the supplied buffer from a file. - * This does multiple reads as necessary. - * Returns the amount read, or -1 on an error. - * A short read is returned on an end of file. - */ -int -fullRead(int fd, char * buf, int len) -{ - int cc; - int total; - - total = 0; - - while (len > 0) - { - cc = read(fd, buf, len); - - if (cc < 0) - return -1; - - if (cc == 0) - break; - - buf += cc; - total+= cc; - len -= cc; - } - - return total; -} - - -/* - * Call system for the specified command and print an error - * message if the execution fails. The exit status of the - * command is returned. - */ -int -trySystem(const char * cmd) -{ - int status; - - status = system(cmd); - - if (status == -1) - fprintf(stderr, "Error starting command: %s\n", cmd); - - return status; -} - - -/* - * Check the status for the most recent system call and complain - * if its value is -1 which indicates it failed. - */ -void -checkStatus(const char * name, int status) -{ - if (status == -1) - perror(name); -} - -/* END CODE */ |