/*- * Copyright (C) 2005-2007 Nick Withers. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "downtime.h" #include #include #include #include #include #include #include #ifdef BSD #include #endif char add_to_unique_string_array(char ***string_array, size_t *array_length, char *string_to_add) { if ((*array_length == 0 || !is_in_string_array(*string_array, *array_length, string_to_add)) && add_to_string_array(string_array, array_length, string_to_add)) return (TRUE); return (FALSE); } /* * Adds the string_to_add to a string array pointed to by string_array of * length *array_length. * * NOTE: * - *string_array holds a pointer to malloc()-ed space and should be freed * by the calling function when it is no longer required. * - add_to_string_array() attempts to free() the memory pointed to by * *string_array when *array_length > 0. For this reason, if the string * array pointed to by *string_array has been touched by anything other * than add_to_string_array(), please ensure that the space it points to was * obtained through malloc() */ char add_to_string_array(char ***string_array, size_t *array_length, char *string_to_add) { return (array_add((void **) string_array, array_length, (void *) &string_to_add, sizeof(string_to_add))); } /* * Adds *add_me to an array of length *length with elements of elem_size pointed to by array * * NOTE: The memory referenced by *array should be free()d when no longer required */ char array_add(void **array, size_t *length, const void *add_me, size_t elem_size) { if (*length == 0) *array = NULL; if ((*array = realloc(*array, (*length + 1) * elem_size)) == NULL) return (FALSE); memmove((*((char **) array) + *length * elem_size), add_me, elem_size); (*length)++; return (TRUE); } /* * * Appends the character append_me to the malloc()-ed original_string * string, which may either be NULL-terminated or be a pointer to NULL * * NOTE: * - *original_string holds a pointer to malloc()-ed space and should be freed * by the calling function when it is no longer required. * - cat_strchar() attempts to free() the memory pointed to by * original_string when it doesn't point to NULL. For this reason, if the string * array pointed to by original_string has been touched by anything other * than add_to_string_array(), please ensure that the space it points to was * obtained through malloc() * */ char cat_strchar(char **original_string, const char append_me) { size_t string_length; if (*original_string == NULL) string_length = 0; else string_length = strlen(*original_string); if (!array_add((void **) original_string, &string_length, &append_me, sizeof (append_me)) || !array_add((void **) original_string, &string_length, "", sizeof (char))) /* Append the NULL character, too */ return (FALSE); return (TRUE); } /* * * Appends the string append_me to original_string in a new, malloc()-ed, string * * NOTE: * - new_string holds a pointer to malloc()ed space and should be freed * by the calling function when it is no longer required. * - original_string is NOT free()d in cat_strings. Therefore, code like * string = cat_strings(string, "-bam"); * where "string" is a pointer to malloc()ed space, causes a memork leak * - trying to append a blank string to a blank string is not treated as a * special case: You'll get a blank string in malloc()ed space back. * This is so that we can fulfill our promise to return a pointer to * malloc()ed space - after all, there will be free()s performed on the * return values of this function! */ char * cat_strings(const char *original_string, const char *append_me) { char *new_string; size_t string_length; string_length = ((original_string == NULL) ? 0 : strlen(original_string)) + ((append_me == NULL) ? 0 : strlen(append_me)); if ((new_string = (char *) malloc(sizeof(char) * (string_length + 1))) == NULL) return (NULL); if (original_string != NULL) { strcpy(new_string, original_string); strcat(new_string, append_me); } else strcpy(new_string, append_me); *(new_string + string_length) = '\0'; /* NULL terminate the string */ return (new_string); } char * find_executable_in_path(char *filename) { size_t i, path_len, path_elements, path_offset; char **paths, *path, *location; if ((path = cat_strings(geteuid() == getuid() ? getenv("PATH") : NULL, _PATH_STDPATH)) == NULL) /* Check if the program is running setuid as another user. If it is, don't add user path environment variables for security reasons */ show_error_dialog(EX_OSERR, "Couldn't store environment PATH. Error: \"%s\" (%d)", strerror(errno), errno); path_len = strlen(path); for (i = 0; i < path_len; i++) /* Replace PATH_SEPARATOR characters in path with NUL character */ { if (*(path + i) == PATH_SEPARATOR) *(path + i) = '\0'; } path_offset = 0; path_elements = 0; while (path_offset < path_len) /* Add each substring of path to paths */ { char *new_path_element = malloc((strlen(path + path_offset) + 1) * sizeof (char)); /* Copy the string to be added into a freshly malloc()ed string. This allows us to free() path, but note that we must now free() each element in paths */ strcpy(new_path_element, (path + path_offset)); if (!add_to_unique_string_array(&paths, &path_elements, new_path_element)) /* If new_path_element isn't added to the array, free() it */ free(new_path_element); path_offset += strlen(path + path_offset) + 1; /* Increment path_offset so that (path + path_offset) will point past the terminating NUL character of the current string on the next run (if any) */ } free(path); for (i = 0; i < path_elements; i++) /* Iterate through each element of paths */ { location = malloc(sizeof (char *) * (strlen(*(paths + i)) + strlen(filename) + 2)); /* + 2: 1 for '/', 1 for '\0' */ strcpy(location, *(paths + i)); strcat(location, "/"); strcat(location, filename); if (access(location, F_OK) == 0 && access(location, X_OK) == 0) { size_t j; for (j = 0; j < path_elements; j++) free(*(paths + j)); free(paths); return (location); } free(location); } for (i = 0; i < path_elements; i++) free(*(paths + i)); free(paths); return (NULL); } char * get_filename_from_path(const char *path) { char *filename; if ((filename = strrchr(path, DIR_SEPARATOR)) != NULL) return (++filename); else return (NULL); } char * get_shutdown_time_left_string(shutdown_t *shutdown) { #define SECONDS_IN_DAY 86400 /* (60 seconds / minute) * (60 minutes / hour) * (24 hours / day) */ struct tm *time_to_shutdown; time_t seconds_to_shutdown; char *str_time_to_shutdown; seconds_to_shutdown = shutdown->shutdown_time - time(NULL); time_to_shutdown = gmtime(&seconds_to_shutdown); if ((time_to_shutdown->tm_year > 70) || (time_to_shutdown->tm_mon > 0) || (time_to_shutdown->tm_mday > 1)) pasprintf(&str_time_to_shutdown, "%ld day%s, %d:%2.2d:%2.2d", (long) (seconds_to_shutdown / SECONDS_IN_DAY), (long) (seconds_to_shutdown / SECONDS_IN_DAY) > 1 ? "s" : "", time_to_shutdown->tm_hour, time_to_shutdown->tm_min, time_to_shutdown->tm_sec); else if (time_to_shutdown->tm_hour > 0) pasprintf(&str_time_to_shutdown, "%d:%2.2d:%2.2d", time_to_shutdown->tm_hour, time_to_shutdown->tm_min, time_to_shutdown->tm_sec); else pasprintf(&str_time_to_shutdown, "%d:%2.2d", time_to_shutdown->tm_min, time_to_shutdown->tm_sec); if (str_time_to_shutdown == NULL) show_error_dialog(EX_OSERR, "pasprintf() returned -1 in get_shutdown_time_left_string(). Error: \"%s\" (%d)", strerror(errno), errno); return (str_time_to_shutdown); #undef SECONDS_IN_DAY } void init_user_specs(user_specs_t *specs) { bzero(specs, sizeof (*specs)); specs->timeout = DEFAULT_TIMEOUT; specs->timeout_unit = DEFAULT_TIMEOUT_UNIT; specs->shutdown_type = DEFAULT_SHUTDOWN_TYPE; specs->remember = DEFAULT_REMEMBER; } char is_in_string_array(char **string_array, size_t array_length, char *string_to_add) { size_t i; for (i = 0; i < array_length; i++) { if (strcmp(string_to_add, *(string_array + i)) == 0) return (TRUE); } return (FALSE); } /* Returns the maximum number of minutes until a scheduled shutdown. So, for instance, if a shutdown was to occur in 6 minutes and 25 seconds, this would return 7 */ long int max_minutes_to_shutdown(shutdown_t *shutdown) { double minutes; minutes = ((double) (shutdown->shutdown_time - time(NULL))) / 60; if (minutes > (long int) minutes) /* Round minutes up */ minutes = (long int) minutes + 1; return ((long int) minutes); } /* * Portable asprintf(). Should behave identically to asprintf() on FreeBSD 6.0-RELEASE */ int pasprintf(char **ret, const char *fmt, ...) { va_list ap; size_t length; va_start(ap, fmt); length = vsnprintf(NULL, 0, fmt, ap); if ((*ret = malloc((length + 1) * sizeof (char))) == NULL) /* + 1 for the trailing NUL character */ { va_end(ap); ret = NULL; /* As with pasprintf() on FreeBSD, set ret = NULL in case of error*/ return (-1); /* As with pasprintf() on FreeBSD, return -1 in case of error. errno will already have been set by malloc() */ } vsnprintf(*ret, length + 1, fmt, ap); va_end(ap); return (length); } /* * Portable vasprintf(). Should behave identically to vasprintf() on FreeBSD 6.0-RELEASE */ int pvasprintf(char **ret, const char *fmt, va_list ap) { size_t length; length = vsnprintf(NULL, 0, fmt, ap); if ((*ret = malloc((length + 1) * sizeof (char))) == NULL) /* + 1 for the trailing NUL character */ { ret = NULL; /* As with pasprintf() on FreeBSD, set ret = NULL in case of error*/ return (-1); /* As with pasprintf() on FreeBSD, return -1 in case of error. errno will already have been set by malloc() */ } vsnprintf(*ret, length + 1, fmt, ap); return (length); } /* * * Trim white-space characters from the beginning and the end of a * NULL-terminated string. A pointer to malloc()ed space containing the trimmed * string is returned which should be freed by the calling function when no * longer required * */ char * trim_white(const char *string) { char *trimmed, *temp; size_t i; while ((*string == ' ' || *string == '\t' || *string == '\n') && *string != '\0') string++; if ((temp = (char *) malloc(sizeof (char) * (strlen(string) + 1))) == NULL) show_error_dialog(EX_OSERR, "malloc() returned NULL in trim_white(). Error: \"%s\" (%d)", strerror(errno), errno); strcpy(temp, string); for (i = strlen(temp); *(temp + i) == '\0' || isspace(*(temp + i)); i--) ; if (i < strlen(temp)) *(temp + i + 1) = '\0'; if ((trimmed = (char *) malloc(sizeof (char) * (strlen(temp) + 1))) == NULL) show_error_dialog(EX_OSERR, "malloc() returned NULL in trim_white(). Error: \"%s\" (%d)", strerror(errno), errno); strcpy(trimmed, temp); free(temp); return (trimmed); }