/* Copyright (c) 2000-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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. */ /** @file kls.c The kls program. */ #include #include #if DK_HAVE_STDLIB_H #include #endif #if DK_HAVE_PROCESS_H #include #endif #include #include #include #include #include #include #include #include #include #if DK_HAVE_OPENSSL_MD5_H #include #endif #if DK_HAVE_OPENSSL_SHA_H #include #endif #if DK_HAVE_OPENSSL_RIPEMD_H #include #endif #include #include "dktools-version.h" #line 86 "kls.ctr" /** System configuration directory. */ static char sysconfdir[] = { DK_SYSCONFDIR }; /** Program group name. */ static char packagename[] = { "dktools" }; /** Type definition needed for sizeof() operator. */ typedef char *PCHAR; /** Kls job. */ typedef struct { PCHAR *filenames; /**< File names to process. */ int names_used; /**< Flag: Names used. */ int symlinks_limited; /**< Flag: Symlink depth limited. */ unsigned long symlinks_allowed; /**< Limit for symlink depth. */ int symlinks_configured; /**< Flag: Symlink limit configured. */ FILE *output_file; /**< Output file to write. */ char *print_list; /**< Output column order. */ int rec; /**< Flag: Recursive listing. */ int rec_configured; /**< Flag: Recursive l configured. */ char *file_types; /**< File types to list. */ int ft_reg; /**< Flag: List regular files. */ int ft_dir; /**< Flag: List directories. */ int ft_pipe; /**< Flag: List pipes. */ int ft_chr; /**< Flag: List character devices. */ int ft_blk; /**< Flag: List block devices. */ int ft_sock; /**< Flag: List sockets. */ int ft_oth; /**< Flag: List other file types. */ int md5_wanted; /**< Flag: Message digest wanted. */ int sz_wanted; /**< Flag: Size wanted. */ int configure_only; /**< Flag: Save conf settings only. */ int unconf_only; /**< Flag: Unconfigure only. */ int show_summary; /**< Flag: Show summary. */ int summary_configured; /**< Flag: Summary flag configured. */ int show_version; /**< Flag: Show version only. */ int show_help; /**< Flag: Show help only. */ int show_configuration; /**< Flag: Show configuration. */ int mdtype_configured; /**< Flag: Message digest configured. */ int mdenc_configured; /**< Flag: Digest encoding configured.*/ dk_long_long_unsigned_t ull_bytes_found; /**< Size found. */ dk_long_long_unsigned_t ull_bytes_in_files; /**< Size of files found. */ dk_long_long_unsigned_t ull_files_found; /**< Numer of files. */ dk_long_long_unsigned_t ull_dirs_found; /**< Number of directories. */ int me_ull_bytes_found; /**< Flag: Overflow in size. */ int me_ull_bytes_in_files; /**< Flag: Overflow in file size. */ int me_ull_files_found; /**< Flag: Overflow in number files. */ int me_ull_dirs_found; /**< Flag: Overflow in number dirs. */ double bytes_found; /**< Size found. */ double bytes_in_files; /**< Bytes in files. */ double files_found; /**< Number of files. */ double dirs_found; /**< Number of directories. */ /* used by run_for_current() */ char *current_name; /**< Name of current object. */ unsigned long current_depth; /**< Depth of current object. */ unsigned long current_symlinks; /**< Symlink depth of object. */ int math_error; /**< Flag: Mathematical error. */ double math_border; /**< Max unsigned long expressed as double. */ int dc_dir; /**< Flag: Directory. */ int dc_contents; /**< Directory contents. */ int dc_configured; /**< Flag: Dir contents configured. */ int remove_cwd_from_name; /**< Flag: Remove cwd from output. */ int remove_cwd_length; /**< Cwd length. */ int size_output_width; /**< Output width. */ int size_output_configured; /**< Flag: Output width configured. */ int stay_on_filesystem; /**< Flag: Stay on filesystem. */ int stay_configured; /**< Flag: stay on filesystem configured. */ int message_digest_type; /**< Message digest type. */ int message_digest_encoding; /**< Message digest encoding. */ } KlsCmd; /** Message digest type: MD5. */ #define MD_TYPE_MD5 0 /** Message digest type: SHA-1. */ #define MD_TYPE_SHA1 1 /** Message digest type: SHA-224. */ #define MD_TYPE_SHA224 2 /** Message digest type: SHA-256. */ #define MD_TYPE_SHA256 3 /** Message digest type: SHA-384. */ #define MD_TYPE_SHA384 4 /** Message digest type: SHA-512. */ #define MD_TYPE_SHA512 5 /** Message digest type: RIPE-MD 160. */ #define MD_TYPE_RIPE160 6 /** Message digest encoding: ASCII-Hex. */ #define MD_ENC_HEX 0 /** Message digest encoding: ASCII-85. */ #define MD_ENC_ASCII85 1 /** Message digest encoding: Reverse ASCII-85. */ #define MD_ENC_RA85 2 /** Output column order. */ static char *allocated_print_list = NULL; /** Directory contents handling. */ static char *allocated_dc = NULL; #if DK_HAVE_FEATURE_BACKSLASH /** File name separator. */ static char fn_sep[] = { "\\" }; #else /** File name separator. */ static char fn_sep[] = { "/" }; #endif /** Messages issued by the program, filled using string finder. */ static char *kls_str[62]; /** String finder data. */ static dk_string_finder_t kls_mesgs[] = { { "/m/00", &(kls_str[0]), "Can not traverse directory \"" }, { "/m/01", &(kls_str[1]), "\"!" }, { "/m/02", &(kls_str[2]), "No information about file \"" }, { "/m/03", &(kls_str[3]), "\" accessable!" }, { "/m/04", &(kls_str[4]), "Failed to estimate current working directory!" }, { "/m/05", &(kls_str[5]), "Not enough memory (RAM or swap space)!" }, { "/m/06", &(kls_str[6]), "Internal error!" }, { "/m/07", &(kls_str[7]), "File \"" }, { "/m/08", &(kls_str[8]), "\" not found!" }, { "/m/09", &(kls_str[9]), "Directories: " }, { "/m/10", &(kls_str[10]), "Files: " }, { "/m/11", &(kls_str[11]), "Bytes in files: " }, { "/m/12", &(kls_str[12]), "Bytes in summary: " }, { "/m/13", &(kls_str[13]), "Directory \"" }, { "/m/14", &(kls_str[14]), "\" exceeds the maximum symlink depth!" }, { "/m/15", &(kls_str[15]), "Support for RSA Data Security, Inc. MD5 Message-Digest not available here!" }, { "/m/16", &(kls_str[16]), "Support for SHA-... message digests not available here!" }, { "/m/17", &(kls_str[17]), "information output order" }, { "/m/18", &(kls_str[18]), "name" }, { "/m/19", &(kls_str[19]), "size" }, { "/m/20", &(kls_str[20]), "type" }, { "/m/21", &(kls_str[21]), "permissions" }, { "/m/22", &(kls_str[22]), "check sum" }, { "/m/23", &(kls_str[23]), "link number" }, { "/m/24", &(kls_str[24]), "creation" }, { "/m/25", &(kls_str[25]), "modification" }, { "/m/26", &(kls_str[26]), "access" }, { "/m/27", &(kls_str[27]), "owner UID" }, { "/m/28", &(kls_str[28]), "owner GID" }, { "/m/29", &(kls_str[29]), "device number" }, { "/m/30", &(kls_str[30]), "relative device number" }, { "/m/31", &(kls_str[31]), "inode number" }, { "/m/32", &(kls_str[32]), "message digest type" }, { "/m/33", &(kls_str[33]), "traverse subdirectories" }, { "/m/34", &(kls_str[34]), "file types" }, { "/m/35", &(kls_str[35]), "regular files" }, { "/m/36", &(kls_str[36]), "directories" }, { "/m/37", &(kls_str[37]), "pipes" }, { "/m/38", &(kls_str[38]), "byte specials" }, { "/m/39", &(kls_str[39]), "block specials" }, { "/m/40", &(kls_str[40]), "sockets" }, { "/m/41", &(kls_str[41]), "others" }, { "/m/42", &(kls_str[42]), "max symlink depth" }, { "/m/43", &(kls_str[43]), "summary" }, { "/m/44", &(kls_str[44]), "on" }, { "/m/45", &(kls_str[45]), "off" }, { "/m/46", &(kls_str[46]), "unlimited" }, { "/m/47", &(kls_str[47]), "directory behaviour" }, { "/m/48", &(kls_str[48]), "directory itself" }, { "/m/49", &(kls_str[49]), "directory contents" }, { "/m/50", &(kls_str[50]), "none" }, { "/m/51", &(kls_str[51]), "Current configuration:" }, { "/m/52", &(kls_str[52]), "stay on file system" }, { "/m/53", &(kls_str[53]), "column width for file size" }, { "/m/54", &(kls_str[54]), "auto" }, { "/m/55", &(kls_str[55]), "message digest encoding" }, { "/m/56", &(kls_str[56]), "Support for RIPEMD-... message digests not available here!" }, { "/m/57", &(kls_str[57]), "Support for SHA-1 message digests not available here!" }, { "/m/58", &(kls_str[58]), "Support for SHA-224 message digests not available here!" }, { "/m/59", &(kls_str[59]), "Support for SHA-256 message digests not available here!" }, { "/m/60", &(kls_str[60]), "Support for SHA-384 message digests not available here!" }, { "/m/61", &(kls_str[61]), "Support for SHA-512 message digests not available here!" }, { NULL, NULL, NULL}, }; #if DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H || DK_HAVE_OPENSSL_RIPEMD_H /** OpenSSL library version. */ static char *openssl_lib_version[] = { "OpenSSL cryptography toolkit implementing the Secure Sockets Layer", " (SSL v2/v3) and Transport Layer Security (TLS v1) network", " protocols and related cryptography standards required by them.", " See http://www.openssl.org for more information.", " The kls program uses the message digest functions provided", " by the OpenSSL library to create checksums (message digests)", " for files using the following algorithms:", #if DK_HAVE_OPENSSL_MD5_H " * MD5:", " RSA Data Security, Inc. MD5 Message-Digest Algorithm", " as published in RFC 1321 (see RFC 1321 for detailed", " copyright and license information,", #endif #if DK_HAVE_OPENSSL_RIPEMD_H " * RIPEMD-160:", " Cryptographic hash function designed by Hans Dobbertin,", " Antoon Bosselaers and Bart Preneel.", #endif #if DK_HAVE_OPENSSL_SHA_H " * SHA-1" #if DK_HAVE_SHA224 " SHA-224" #endif #if DK_HAVE_SHA256 " SHA-256" #endif #if DK_HAVE_SHA384 " SHA-384" #endif #if DK_HAVE_SHA512 " SHA-512" #endif ":", " SHA-... messages digests as published in the FIPS", " publications.", #endif NULL }; #endif /** Flag: Error already printed. */ #if !(DK_HAVE_OPENSSL_MD5_H && DK_HAVE_OPENSSL_SHA_H && DK_HAVE_OPENSSL_RIPEMD_H) static int error_type_printed = 0; #endif #if DK_HAVE_LONG_LONG_INT /** Convert unsigned long long to string. Use MS specific format string when using MS C compiler. @param buffer Result buffer. @param ull Value to convert. */ static void ull_to_string DK_P2(char *,buffer, long long unsigned, ull) { #if _MSC_VER >= 1100 sprintf(buffer, "%I64u", ull); #else sprintf(buffer, "%llu", ull); #endif } #else /** Convert unsigned long to string. @param buffer Result buffer. @param ull Value to convert. */ static void ull_to_string DK_P2(char *,buffer, long unsigned, ull) { sprintf(buffer, "%lu", ull); } #endif /** Print size as unsigned long long or double value for size. @param cmd Kls job. @param ull Unsigned long long value. @param d Double value. @param ma Print double instead of ull. */ static void pr_ull_or_double DK_P4(KlsCmd *,cmd, dk_long_long_unsigned_t,ull, double,d, int,ma) { char buffer[32], *stptr; size_t in_use = 0, field_length = 0, i = 0; #if DK_HAVE_LONG_LONG_INT field_length = 21; #else field_length = 11; #endif if(ma) { sprintf(buffer, "%20.0lf", d); stptr = dkstr_start(buffer, NULL); } else { ull_to_string(buffer, ull); stptr = buffer; } if(cmd->size_output_width > 0) { field_length = cmd->size_output_width; } in_use = 0; if(stptr) { in_use = strlen(stptr); } if(ma) { in_use++; } if((in_use <= field_length) && stptr) { if(cmd->size_output_width != -1) { for(i = in_use; i < field_length; i++) { fputc(' ', cmd->output_file); } } if(ma) { fputc('~', cmd->output_file); } fputs(stptr, cmd->output_file); } else { for(i = 0; i < field_length; i++) { fputc('~', cmd->output_file); } } } /** Initialize kls job. @param cmd Kls job. */ static void cmd_init DK_P1(KlsCmd *,cmd) { cmd->remove_cwd_from_name = 0; cmd->remove_cwd_length = 0; cmd->math_error = 0; cmd->filenames = NULL; cmd->names_used = 0; cmd->symlinks_limited = 0; cmd->symlinks_allowed = 0UL; cmd->symlinks_configured = 0; cmd->mdtype_configured = 0; cmd->mdenc_configured = 0; cmd->output_file = NULL; cmd->print_list = NULL; cmd->rec = 0; cmd->rec_configured = 0; cmd->file_types = NULL; cmd->configure_only = 0; cmd->unconf_only = 0; cmd->show_summary = 0; cmd->summary_configured = 0; cmd->show_version = 0; cmd->show_help = 0; cmd->show_configuration = 0; cmd->bytes_found = 0.0; cmd->files_found = 0.0; cmd->dirs_found = 0.0; cmd->bytes_in_files = 0.0; cmd->ull_bytes_found = DK_ZERO_LONG_LONG_UNSIGNED; cmd->ull_bytes_in_files = DK_ZERO_LONG_LONG_UNSIGNED; cmd->ull_files_found = DK_ZERO_LONG_LONG_UNSIGNED; cmd->ull_dirs_found = DK_ZERO_LONG_LONG_UNSIGNED; cmd->me_ull_bytes_found = 0; cmd->me_ull_bytes_in_files = 0; cmd->me_ull_files_found = 0; cmd->me_ull_dirs_found = 0; cmd->ft_reg = 0; cmd->ft_dir = 0; cmd->ft_pipe = 0; cmd->ft_chr = 0; cmd->ft_blk = 0; cmd->ft_sock = 0; cmd->ft_oth = 0; cmd->md5_wanted = 0; cmd->sz_wanted = 0; cmd->math_border = dkma_ul_to_double(0xFFFFFFFFUL); cmd->dc_dir = 0; cmd->dc_contents = 0; cmd->dc_configured = 0; cmd->size_output_width = 0; cmd->size_output_configured = 0; cmd->stay_on_filesystem = 0; cmd->stay_configured = 0; cmd->message_digest_type = MD_TYPE_SHA1; cmd->message_digest_encoding = MD_ENC_HEX; } /** Default column order. */ static char default_print_list[] = { "tn" }; /** Default list of file types to show. */ static char default_file_types[] = { "fd" }; /** Preference key for column order. */ static char pn_print_list[] = { "/print" }; /** Preference key for recursive listing. */ static char pn_rec[] = { "/recursive" }; /** Preference key to choose file types to show. */ static char pn_type[] = { "/type" }; /** Preference key for writing summary information. */ static char pn_summary[] = { "/summary" }; /** Preference key for symlink depth. */ static char pn_links[] = { "/links" }; /** Preference key for width. */ static char pn_width[] = { "/width" }; /** Preference key how to handle directories. */ static char pn_dir[] = { "/directory" }; /** Preference key for "stay-on-filesystem" flag. */ static char pn_stay[] = { "/stay-on-filesystem" }; /** Preference key to choose message digest. */ static char pn_digest[] = { "/message-digest" }; /** Preference key for message digest encoding. */ static char pn_mdenc[] = { "/message-digest-encoding" }; /** Preference value "on". */ static char pv_on[] = { "on" }; /** Preference value "off". */ static char pv_off[] = { "off" }; /** Preference value "unlimited" for symlink depth. */ static char pv_unlimited[] = { "unlimited" }; /** Message digest types. */ static char *digest_types[] = { "MD5", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512", "RIPEMD-160", NULL }; /** Encodings for messages digests. */ static char *digest_encodings[] = { "HEX", "ASCII-85", "R-ASCII-85", NULL }; /** Application. */ static dk_app_t *app = NULL; #ifndef MIN /** Minimum of two values. */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif /** Retrieve settings from preferences. The settings from here are overwritten by command line options. @param cmd Kls job. @param my_info Address of pointer to column order string. @param my_types Address of pointer to file type string. */ static void complete_from_prefs DK_P3(KlsCmd *,cmd, char **,my_info, char **,my_types) { char line[256], *cptr; unsigned long x; if(!(cmd->mdtype_configured)) { if(dkapp_get_pref(app, pn_digest, line, sizeof(line), 0)) { cmd->message_digest_type = dkstr_array_index( digest_types, line, 0 ); if(cmd->message_digest_type < 0) { cmd->message_digest_type = MD_TYPE_SHA1; } } } if(!(cmd->mdenc_configured)) { if(dkapp_get_pref(app, pn_mdenc, line, sizeof(line), 0)) { cmd->message_digest_encoding = dkstr_array_index( digest_encodings, line, 0 ); if(cmd->message_digest_encoding < 0) { cmd->message_digest_encoding = MD_ENC_HEX; } } } if(!(cmd->print_list)) { if(dkapp_get_pref(app, pn_print_list, line, sizeof(line), 0)) { cptr = dkstr_dup(line); if(cptr) { *my_info = cptr; cmd->print_list = cptr; } } } if(!(cmd->file_types)) { if(dkapp_get_pref(app, pn_type, line, sizeof(line), 0)) { cptr = dkstr_dup(line); if(cptr) { *my_types = cptr; cmd->file_types = cptr; } } } if(!(cmd->rec_configured)) { if(dkapp_get_pref(app, pn_rec, line, sizeof(line), 0)) { if(dkstr_is_on(line)) { cmd->rec = 1; } else { cmd->rec = 0; } cmd->rec_configured = 1; } } if(!(cmd->symlinks_configured)) { if(dkapp_get_pref(app, pn_links, line, sizeof(line), 0)) { cmd->symlinks_configured = 1; if(sscanf(line, "%lu", &x) == 1) { cmd->symlinks_limited = 1; cmd->symlinks_allowed = x; } else { cmd->symlinks_limited = 0; } } } if(!(cmd->size_output_configured)) { if(dkapp_get_pref(app, pn_width, line, sizeof(line), 0)) { int i; if(sscanf(line, "%d", &i) == 1) { if(i < -1) i = -1; if(i > 20) i = 20; cmd->size_output_width = i; cmd->size_output_configured = 1; } } } if(!(cmd->summary_configured)) { if(dkapp_get_pref(app, pn_summary, line, sizeof(line), 0)) { cmd->summary_configured = 1; if(dkstr_is_on(line)) { cmd->show_summary = 1; } else { cmd->show_summary = 0; } } } if(!(cmd->dc_configured)) { if(dkapp_get_pref(app, pn_dir, line, sizeof(line), 0)) { cmd->dc_configured= 1; cptr = line; while(*cptr) { switch(*cptr) { case 'd' : cmd->dc_dir = 1; break; case 'c' : cmd->dc_contents = 1; break; } cptr++; } } } if(!(cmd->stay_configured)) { if(dkapp_get_pref(app, pn_stay, line, sizeof(line), 0)) { cmd->stay_configured = 1; cmd->stay_on_filesystem = dkstr_is_on(line); } } } /** Version number string. */ static char the_version_number[] = { VERSNUMB } ; /** License terms. */ static char *license_terms[] = { "Redistribution and use in source and binary forms, with or without", "modification, are permitted provided that the following conditions are met:", "* Redistributions of source code must retain the above copyright notice, this", " list of conditions and the following disclaimer.", "* 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.", "* Neither the name of the Dirk Krause nor the names of other contributors may", " be used to endorse or promote products derived from this software without", " specific prior written permission.", "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE COPYRIGHT OWNER 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.", #if (DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H || DK_HAVE_OPENSSL_RIPEMD_H) "", "This program uses the OpenSSL library.", "This product includes cryptographic software written by", "Eric Young (eay@cryptsoft.com).", #endif NULL }; /** Print version number. */ static void print_version DK_P0() { char **ptr; printf("\n"); printf( "kls (part of the dktools collection, version %s)\n", the_version_number ); printf("Copyright (C) 2002-2010 Dipl.-Ing. D. Krause\n"); printf("http://dktools.sourceforge.net/\n"); printf( "File sizes reported by the OS use %lu bits\n", (8UL * dksf_filesize_bytes()) ); printf( "File size calculations in kls use %lu bits\n", (8UL * dksf_long_long_bytes()) ); printf("Message digest types: MD5 RIPEMD-160 SHA-1"); #if DK_HAVE_SHA224 printf(" SHA-224"); #endif #if DK_HAVE_SHA256 printf(" SHA-256"); #endif #if DK_HAVE_SHA384 printf(" SHA-384"); #endif #if DK_HAVE_SHA512 printf(" SHA-512"); #endif printf("\n\n"); ptr = license_terms; while(*ptr) { fputs(*(ptr++), stdout); fputc('\n', stdout); } printf("\nLibraries used:\n\n"); ptr = dklic_get(); while(*ptr) { fputs(*(ptr++), stdout); fputc('\n', stdout); } fputc('\n', stdout); } /** Default help text, printed if help text file is not found. */ static char *help_text[] = { "kls - ls-replacement", "====================", "", "Usage:", "------", "", "kls [-o ] []", "", " lists the selected files as specified in the options. Command line", " options overwrite permanent options.", " Option -o redirects output to the given file.", "", "kls -c ", " ", " establishes the given options as permanent options.", "", "kls -u", "", " removes all permanent options.", "", "kls -C", "", " shows all permanent options.", "", "Options:", "---------", "", "-p --print=", " issues the following information for each file", " n ... file name", " s ... file size in bytes", " t ... file type", " p ... permissions", " x ... check sum", " l ... link number", " c ... creation timestamp", " m ... last modification timestamp", " a ... last access timestamp", " u ... owner UID", " g ... owner GID", " d ... device number", " r ... relative device number", " i ... inode number", "-m --message-digest=", " chooses a message digest type", " MD5 RSA Data Security, Inc. MD5 message-digest", " SHA-1 SHA-1 message-digest", " SHA-224 SHA-224 message digest", " SHA-256 SHA-256 message digest", " SHA-384 SHA-384 message digest", " SHA-512 SHA-512 message digest", " RIPEMD-160 RIPEMD-160 message digest", "-e --encoding=", " chooses the encoding of the message digest", " HEX hexadecimal encoding (default)", " ASCII-85 ASCII-85 encoding", " R-ASCII-85 reverse ASCII-85 encoding", "-r --recursive", " traverses subdirectories too", "-t --type=", " restricts files to inspect to a set of given types:", " f ... regular files", " d ... directories", " p ... pipes", " c ... character special devices", " b ... block special devices", " s ... sockets", " o ... all other files", "-l --links=", " restricts the depth of symbolic links to follow", " (specify a number or \"unlimited\")", "-f --stay-on-filesystem", " stops at filesystem borders", "-s --summary", " gives a summary before quitting.", "-d specifies how to handle directory names from the", " command line. If the string contains a \"d\" the", " program issues information about the directory", " itself, if it contains a \"c\" it lists the contents.", " One can combine \"d\" and \"c\".", "", "kls combines features from both ls and du. Output is configurable,", "you can specify the order of columns.", "", "The program uses the dkapp library and it's preferences mechanism", "to provide permanent options.", "", "The following preferences are recognized:", "", "/directory a string telling how to handle directory names given on", " the command line. See the \"-d\" option.", "", "/recursive is a boolean flag specifying whether or not to traverse", " subdirectories. See \"-r\".", "", "/links is a string specifying the maximum depth of", " symbolic links to follow. See \"-l\".", "", "/print specifies the order of output columns. See \"-p\".", "", "/summary chooses whether or not to print a summary. See \"-s\".", "", "/type selects the file types to inspect. See \"-t\".", "", "One can set permanent options using \"-c\", i.e. when running", "", " kls -c -ptsn -ddc -s", "", "you get no output, the options \"-ptsn -ddc -s\" are stored as", "permanent options instead.", "If you run", "", " kls ", "", "the program behaves as if the options \"-ptsn -ddc -s\" were specified.", "", "To remove all permanent options, use", "", " kls -u", "", NULL }; /** Directory entry. */ struct _kls_dir_entry_ { struct _kls_dir_entry_ *prev; /**< Parent entry. */ dk_dir_t *dir; /**< Directory traversal. */ dk_stat_t *st; /**< Information about entry. */ char *name; /**< File/directory name. */ double bytes_found; /**< Size (including all contents). */ dk_long_long_unsigned_t ull_bytes_found; /**< Size as unsigned long. */ int ull_math_error; /**< Flag: Numeric overflow. */ unsigned long ll; /**< Symlink level. */ /* ---- for traversal ---- */ dk_stat_t *testst; /**< Information about entry. */ char *fn; /**< Entry name. */ char *sn; /**< Short entry name. */ int ft; /**< Entry type. */ }; /** Directory entry. */ typedef struct _kls_dir_entry_ DirEntry; /** Create new structure for directory entry. @param name Directory entry name. @param parent Entry for the parent directory. @return Pointer to new entry on success, NULL on error. */ static DirEntry * dir_entry_new DK_P2(char *,name, DirEntry *,parent) { DirEntry *back = NULL; dk_dir_t *newdir; dk_stat_t *newstat; char *newname; back = dk_new(DirEntry,1); newdir = dkdir_open(name); newstat = dkstat_open(name); newname = dkstr_dup(name); if(back && newdir && newstat && newname) { back->prev = parent; back->dir = newdir; back->st = newstat; back->name = newname; /* back->bytes_found = dkma_ull_to_double(dkstat_size(newstat)); */ back->bytes_found = 0.0; back->ull_bytes_found = DK_ZERO_LONG_LONG_UNSIGNED; back->ull_math_error = 0; back->ll = 0UL; if(parent) { back->ll = parent->ll; } } else { if(back) { dk_delete(back); back = NULL; } if(newdir) { dkdir_close(newdir); } if(newstat) { dkstat_close(newstat); } if(newname) { dk_delete(newname); } back = NULL; } return back; } /** Convert file type to character. @param ft File type. @return Character representing the file type in listing. */ static char ft_to_char DK_P1(int, ft) { char back; back = '-'; if(ft & DK_FT_SYMLINK) { switch(ft & (~(DK_FT_SYMLINK))) { case DK_FT_REG : back = 'l' ; break; case DK_FT_DIR : back = 'D' ; break; case DK_FT_FIFO : back = 'P' ; break; case DK_FT_CHR : back = 'C' ; break; case DK_FT_BLK : back = 'B' ; break; case DK_FT_SOCKET : back = 'S' ; break; default : back = 'O' ; break; } } else { switch(ft) { case DK_FT_REG : back = '-' ; break; case DK_FT_DIR : back = 'd' ; break; case DK_FT_FIFO : back = 'p' ; break; case DK_FT_CHR : back = 'c' ; break; case DK_FT_BLK : back = 'b' ; break; case DK_FT_SOCKET : back = 's' ; break; default : back = 'o' ; break; } } return back; } /** Check whether or not we need to traverse the subdirectory. @param cmd Kls job. @param de Directory entry. @param st Information about the directory entry. @return 1 for traverse, 0 for no traverse. */ static int must_go_sub DK_P3(KlsCmd *,cmd, DirEntry *,de, dk_stat_t *,st) { int back = 0; int rec; char *logmsg[3]; #if !DK_HAVE_NO_INODES DirEntry *current; unsigned long st_device, st_inode, current_device, current_inode; #endif if(de) { if((cmd->rec) || (cmd->sz_wanted)) { back = 1; } } else { if((cmd->dc_contents) || (cmd->rec) || (cmd->sz_wanted)) { back = 1; } } rec = 0; if(back) { if(dkstat_filetype(st) & DK_FT_SYMLINK) { if(cmd->symlinks_limited) { back = 0; if(de) { if((de->ll) < (cmd->symlinks_allowed)) { back = 1; } } else { if(cmd->symlinks_allowed) { back = 1; } } } else { } #if !DK_HAVE_NO_INODES if(back) { /* Rekursivitaets-Test */ st_device = dkstat_device(st); st_inode = dkstat_inode(st); current = de; while(current && back) { current_inode = dkstat_inode(current->st); if((current_inode == st_inode) && current_inode) { current_device = dkstat_device(current->st); if(current_device == st_device) { back = 0; rec = 1; } } current = current->prev; } } #endif } if(!back) { if(!rec) { logmsg[0] = kls_str[13]; logmsg[1] = dkdir_get_fullname(de->dir); logmsg[2] = kls_str[14]; dkapp_log_msg(app, DK_LOG_LEVEL_WARNING, logmsg, 3); } } } if(back && (cmd->stay_on_filesystem)) { if(de && st) { if(dkstat_device(de->st) != dkstat_device(st)) { back = 0; } } } return back; } #if (DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H || DK_HAVE_OPENSSL_RIPEMD_H) /** Hexadecimal numbers. */ static char hex_digits[] = { "0123456789abcdef" }; #endif /** Check directory depth. Printing is restricted to a directory depth. @param cmd Kls job. @param de Current directory entry. @param st Information about the directory entry. @param name File/directory name. @return 1 on success, 0 on error. */ static int can_print DK_P4(KlsCmd *,cmd, DirEntry *,de, dk_stat_t *,st, char *,name) { int back = 1; if(cmd->remove_cwd_from_name) { if(cmd->remove_cwd_length >= 0) { if(strlen(name) <= (size_t)(cmd->remove_cwd_length)) { back = 0; } } } return back; } #ifdef NEED_LOGMSG #undef NEED_LOGMSG #endif /** Compile condition: Variable logmsg is needed. */ #define NEED_LOGMSG 1 #if DK_HAVE_OPENSSL_MD5_H #if DK_HAVE_OPENSSL_SHA_H #if DK_HAVE_OPENSSL_RIPEMD_H #if DK_HAVE_SHA224 #if DK_HAVE_SHA256 #if DK_HAVE_SHA384 #if DK_HAVE_SHA512 #undef NEED_LOGMSG #endif #endif #endif #endif #endif #endif #endif /** Create digest (file checksum). @param cmd Kls job. @param b Result buffer. @param sz Size of \a b in bytes. @param de Directory entry. @param st Information about the directory entry. @param name File/directory name. */ static void create_digest DK_P6(KlsCmd *,cmd, char *,b, size_t,sz, DirEntry *,de, dk_stat_t *,st, char *,name) { #if NEED_LOGMSG char *logmsg[16]; #endif #if (DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H || DK_HAVE_OPENSSL_RIPEMD_H) unsigned char buffer[512]; /**< Binary message digest. */ size_t u_buffer = 0; /**< Length of binary message digest. */ FILE *f = NULL; /**< File to read. */ unsigned char not_regular; /**< Flag: not a regular file. */ int bytes_read; /**< Number of bytes read from file. */ size_t i; /**< Used in loop to set '-'. */ #endif #if DK_HAVE_OPENSSL_MD5_H MD5_CTX md5_ctx; #endif #if DK_HAVE_OPENSSL_SHA_H SHA_CTX sha_ctx; #if DK_HAVE_SHA256 || DK_HAVE_SHA224 SHA256_CTX sha256_ctx; #endif #if DK_HAVE_SHA512 || DK_HAVE_SHA384 SHA512_CTX sha512_ctx; #endif #endif #if DK_HAVE_OPENSSL_RIPEMD_H RIPEMD160_CTX ripemd160_ctx; #endif *b = '\0'; #if (DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H || DK_HAVE_OPENSSL_RIPEMD_H) u_buffer = 0; not_regular = 0x00; switch(cmd->message_digest_type) { case MD_TYPE_MD5: { /* 16 bytes */ #if DK_HAVE_OPENSSL_MD5_H if((dkstat_filetype(st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) { f = dkapp_fopen(app, name, "rb"); if(f) { MD5_Init(&md5_ctx); do { bytes_read = (int)fread(buffer,1,sizeof(buffer),f); if(bytes_read > 0) { MD5_Update(&md5_ctx, buffer, (size_t)bytes_read); } } while(bytes_read > 0); MD5_Final(buffer, &md5_ctx); u_buffer = 16; fclose(f); } else { dkapp_err_fopenr(app, name); } } else { not_regular = 0x01; } #else if(!(error_type_printed & 1)) { error_type_printed |= 1; logmsg[0] = kls_str[15]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } #endif } break; case MD_TYPE_SHA1: { /* 20 bytes */ #if DK_HAVE_OPENSSL_SHA_H if((dkstat_filetype(st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) { f = dkapp_fopen(app, name, "rb"); if(f) { SHA1_Init(&sha_ctx); do { bytes_read = (int)fread(buffer,1,sizeof(buffer),f); if(bytes_read > 0) { SHA1_Update(&sha_ctx, buffer, (size_t)bytes_read); } } while(bytes_read > 0); SHA1_Final(buffer, &sha_ctx); u_buffer = 20; fclose(f); } else { dkapp_err_fopenr(app, name); } } else { not_regular = 0x01; } #else if(!(error_type_printed & 2)) { error_type_printed |= 2; logmsg[0] = kls_str[57]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } #endif } break; case MD_TYPE_SHA224: { /* 28 bytes */ #if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA224 if((dkstat_filetype(st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) { f = dkapp_fopen(app, name, "rb"); if(f) { SHA224_Init(&sha256_ctx); do { bytes_read = (int)fread(buffer,1,sizeof(buffer),f); if(bytes_read > 0) { SHA224_Update(&sha256_ctx, buffer, (size_t)bytes_read); } } while(bytes_read > 0); SHA224_Final(buffer, &sha256_ctx); u_buffer = 28; fclose(f); } else { dkapp_err_fopenr(app, name); } } else { not_regular = 0x01; } #else if(!(error_type_printed & 2)) { error_type_printed |= 2; logmsg[0] = kls_str[58]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } #endif } break; case MD_TYPE_SHA256: { /* 32 bytes */ #if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA256 if((dkstat_filetype(st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) { f = dkapp_fopen(app, name, "rb"); if(f) { SHA256_Init(&sha256_ctx); do { bytes_read = (int)fread(buffer,1,sizeof(buffer),f); if(bytes_read > 0) { SHA256_Update(&sha256_ctx, buffer, (size_t)bytes_read); } } while(bytes_read > 0); SHA256_Final(buffer, &sha256_ctx); u_buffer = 32; fclose(f); } else { dkapp_err_fopenr(app, name); } } else { not_regular = 0x01; } #else if(!(error_type_printed & 2)) { error_type_printed |= 2; logmsg[0] = kls_str[59]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } #endif } break; case MD_TYPE_SHA384: { /* 48 bytes */ #if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA384 if((dkstat_filetype(st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) { f = dkapp_fopen(app, name, "rb"); if(f) { SHA384_Init(&sha512_ctx); do { bytes_read = (int)fread(buffer,1,sizeof(buffer),f); if(bytes_read > 0) { SHA384_Update(&sha512_ctx, buffer, (size_t)bytes_read); } } while(bytes_read > 0); SHA384_Final(buffer, &sha512_ctx); u_buffer = 48; fclose(f); } else { dkapp_err_fopenr(app, name); } } else { not_regular = 0x01; } #else if(!(error_type_printed & 2)) { error_type_printed |= 2; logmsg[0] = kls_str[60]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } #endif } break; case MD_TYPE_SHA512: { /* 64 bytes */ #if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA512 if((dkstat_filetype(st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) { f = dkapp_fopen(app, name, "rb"); if(f) { SHA512_Init(&sha512_ctx); do { bytes_read = (int)fread(buffer,1,sizeof(buffer),f); if(bytes_read > 0) { SHA512_Update(&sha512_ctx, buffer, (size_t)bytes_read); } } while(bytes_read > 0); SHA512_Final(buffer, &sha512_ctx); u_buffer = 64; fclose(f); } else { dkapp_err_fopenr(app, name); } } else { not_regular = 0x01; } #else if(!(error_type_printed & 2)) { error_type_printed |= 2; logmsg[0] = kls_str[61]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } #endif } break; case MD_TYPE_RIPE160: { /* 20 bytes */ #if DK_HAVE_OPENSSL_RIPEMD_H if((dkstat_filetype(st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) { f = dkapp_fopen(app, name, "rb"); if(f) { RIPEMD160_Init(&ripemd160_ctx); do { bytes_read = (int)fread(buffer,1,sizeof(buffer),f); if(bytes_read > 0) { RIPEMD160_Update(&ripemd160_ctx, buffer, (size_t)bytes_read); } } while(bytes_read > 0); RIPEMD160_Final(buffer, &ripemd160_ctx); u_buffer = 20; fclose(f); } else { dkapp_err_fopenr(app, name); } } else { not_regular = 0x01; } #else if(!(error_type_printed & 4)) { error_type_printed |= 4; logmsg[0] = kls_str[56]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } #endif } break; } if(u_buffer) { switch(cmd->message_digest_encoding) { case MD_ENC_ASCII85: { dkenc_bin_to_a85(b, sz, (char *)buffer, u_buffer); } break; case MD_ENC_RA85: { dkenc_bin_to_ra85(b, sz, (char *)buffer, u_buffer); } break; default: { dkenc_bin_to_hex(b, sz, (char *)buffer, u_buffer); } break; } } else { if(not_regular) { if(not_regular == 0x01) { u_buffer = 0; switch(cmd->message_digest_type) { case MD_TYPE_MD5: { /* 16 bytes */ #if DK_HAVE_OPENSSL_MD5_H u_buffer = 16; #endif } break; case MD_TYPE_SHA1: { /* 20 bytes */ #if DK_HAVE_OPENSSL_SHA_H u_buffer = 20; #endif } break; case MD_TYPE_SHA224: { /* 28 bytes */ #if DK_HAVE_OPENSSL_SHA_H u_buffer = 28; #endif } break; case MD_TYPE_SHA256: { /* 32 bytes */ #if DK_HAVE_OPENSSL_SHA_H u_buffer = 32; #endif } break; case MD_TYPE_SHA384: { /* 48 bytes */ #if DK_HAVE_OPENSSL_SHA_H u_buffer = 48; #endif } break; case MD_TYPE_SHA512: { /* 64 bytes */ #if DK_HAVE_OPENSSL_SHA_H u_buffer = 64; #endif } break; case MD_TYPE_RIPE160: { /* 20 bytes */ #if DK_HAVE_OPENSSL_RIPEMD_H u_buffer = 20; #endif } break; } if(u_buffer) { switch(cmd->message_digest_encoding) { case MD_ENC_ASCII85: case MD_ENC_RA85: { u_buffer = dkenc_size_bin_to_a85(u_buffer); for(i = 0; i < u_buffer; i++) b[i] = ' '; b[u_buffer - 1] = '\0'; } break; default: { u_buffer = dkenc_size_bin_to_hex(u_buffer); for(i = 0; i < u_buffer; i++) b[i] = '-'; b[u_buffer - 1] = '\0'; } break; } } } } } #endif } /** Print one directory entry. @param cmd Kls job. @param de Directory entry. @param st Information about the directory entry. @param name File/directory name. */ static void print_entry DK_P4(KlsCmd *,cmd, DirEntry *,de, dk_stat_t *,st, char *,name) { char *cptr; int is_first, last_was_type, perms, xul_err, lgt; dk_long_long_unsigned_t xul; #if (DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H || DK_HAVE_OPENSSL_RIPEMD_H) char digbuf[256]; int i; #endif if(can_print(cmd,de,st,name)) { is_first = 1; last_was_type = 0; #if (DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H) digbuf[0] = '\0'; if(cmd->md5_wanted) { create_digest(cmd, digbuf, sizeof(digbuf), de, st, name); } else { } #endif if(cmd->print_list) { cptr = cmd->print_list; while(*cptr) { if(!is_first) { if((!last_was_type) || (!(*cptr == 'p'))) { fputc(' ', cmd->output_file); } } switch(*cptr) { case 'n': { if(cmd->remove_cwd_from_name) { lgt = strlen(name); if(lgt > (cmd->remove_cwd_length)) { fputs(&(name[cmd->remove_cwd_length]), cmd->output_file); } } else { fputs(name, cmd->output_file); } } break; #if (DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H) case 'x': { /* fputs(digest, cmd->output_file); */ fputs(digbuf, cmd->output_file); } break; #endif case 's': { xul_err = 0; if(de) { pr_ull_or_double( cmd, de->ull_bytes_found, de->bytes_found, de->ull_math_error ); } else { xul_err = 0; xul = dkstat_size_ok(st, &xul_err); pr_ull_or_double(cmd, xul, dkma_ull_to_double(xul), xul_err); } } break; case 't': { fputc(ft_to_char(dkstat_filetype(st)), cmd->output_file); } break; case 'p': { perms = dkstat_permissions(st); fputc(((perms & DK_PERM_U_READ) ? 'r' : '-'), cmd->output_file); fputc(((perms & DK_PERM_U_WRITE)?'w':'-'), cmd->output_file); if(perms & DK_PERM_SUID) { fputc(((perms & DK_PERM_U_EXECUTE) ? 's' : 'S'), cmd->output_file); } else { fputc(((perms & DK_PERM_U_EXECUTE) ? 'x' : '-'), cmd->output_file); } fputc(((perms & DK_PERM_G_READ) ? 'r' : '-'), cmd->output_file); fputc(((perms & DK_PERM_G_WRITE) ? 'w' : '-'),cmd->output_file); if(perms & DK_PERM_SGID) { if((dkstat_filetype(st) & (~(DK_FT_SYMLINK))) == DK_FT_DIR) { fputc('l', cmd->output_file); } else { fputc(((perms & DK_PERM_G_EXECUTE) ? 's' : 'S'), cmd->output_file); } } else { fputc(((perms & DK_PERM_G_EXECUTE) ? 'x' : '-'), cmd->output_file); } fputc(((perms & DK_PERM_O_READ) ? 'r' : '-'), cmd->output_file); fputc(((perms & DK_PERM_O_WRITE) ? 'w' : '-'), cmd->output_file); if(perms & DK_PERM_VTX) { fputc(((perms & DK_PERM_O_EXECUTE) ? 't' : 'T'), cmd->output_file); } else { fputc(((perms & DK_PERM_O_EXECUTE) ? 'x' : '-'), cmd->output_file); } } break; case 'l': { if(cmd->size_output_width != -1) { fprintf(cmd->output_file, "%10lu", dkstat_nlinks(st)); } else { fprintf(cmd->output_file, "%lu", dkstat_nlinks(st)); } } break; case 'c': { fputs(dkstat_ctime(st), cmd->output_file); } break; case 'm': { fputs(dkstat_mtime(st), cmd->output_file); } break; case 'a': { fputs(dkstat_atime(st), cmd->output_file); } break; case 'u': { if(cmd->size_output_width != -1) { fprintf(cmd->output_file, "%10lu", dkstat_uid(st)); } else { fprintf(cmd->output_file, "%lu", dkstat_uid(st)); } } break; case 'g': { if(cmd->size_output_width != -1) { fprintf(cmd->output_file, "%10lu", dkstat_gid(st)); } else { fprintf(cmd->output_file, "%lu", dkstat_gid(st)); } } break; case 'd': { if(cmd->size_output_width != -1) { fprintf(cmd->output_file, "%10lu", dkstat_device(st)); } else { fprintf(cmd->output_file, "%lu", dkstat_device(st)); } } break; case 'r': { if(cmd->size_output_width != -1) { fprintf(cmd->output_file, "%10lu", dkstat_rdevice(st)); } else { fprintf(cmd->output_file, "%lu", dkstat_rdevice(st)); } } break; case 'i': { if(cmd->size_output_width != -1) { fprintf(cmd->output_file, "%10lu", dkstat_inode(st)); } else { fprintf(cmd->output_file, "%lu", dkstat_inode(st)); } } break; } last_was_type = ((*cptr == 't') ? 1 : 0); is_first = 0; cptr++; } fputc('\n', cmd->output_file); } else { fputs(name, cmd->output_file); fputc('\n', cmd->output_file); } } else { } } /** Output one entry (check with required file types before printing). @param cmd Kls job. @param de Directory entry. @param st Information about the directory entry. @param name Directory entry name. */ static void output_for_entry DK_P4(KlsCmd *,cmd, DirEntry *,de, dk_stat_t *,st, char *,name) { int ok; ok = 0; switch(dkstat_filetype(st) & (~(DK_FT_SYMLINK))) { case DK_FT_REG : { if(cmd->ft_reg) ok = 1; } break; case DK_FT_DIR : { if(cmd->ft_dir) ok = 1; } break; case DK_FT_FIFO : { if(cmd->ft_pipe) ok = 1; } break; case DK_FT_CHR : { if(cmd->ft_chr) ok = 1; } break; case DK_FT_BLK : { if(cmd->ft_blk) ok = 1; } break; case DK_FT_SOCKET : { if(cmd->ft_sock) ok = 1; } break; default : { if(cmd->ft_oth) ok = 1; } break; } if(ok) { print_entry(cmd,de,st,name); } } /** Check with directory depth, print if necessary. @param cmd Kls job. @param current Current directory entry. @param dir Flag: current entry is directory. @return 1 on success, 0 on error. */ static int output_check DK_P3(KlsCmd *,cmd, DirEntry *,current, int,dir) { int back = 0; if(cmd->rec) { back = 1; } else { if(current->prev) { if(!((current->prev)->prev)) { if(dir) { /* dir aaa/bbb */ if(cmd->dc_contents) { back = 1; } else { if(!(cmd->dc_dir)) { back = 1; } } } else { /* file aaa/bbb/ccc */ } } } else { if(dir) { /* dir aaa */ if(cmd->dc_dir) { back = 1; } else { if(!(cmd->dc_contents)) { back = 1; } } } else { /* file aaa/bbb */ if(cmd->dc_contents) { back = 1; } else { if(!(cmd->dc_dir)) { back = 1; } } } } } return back; } /** Run for a current directory . @param cmd Kls job. @return 1 on success, 0 on error. */ static int run_for_current DK_P1(KlsCmd *,cmd) { int back = 0, ft, math_err, old_err, dnt; DirEntry *current, *next; dk_stat_t *st; char *cptr, *sn; char *logmsgs[8]; dk_long_long_unsigned_t xul; current = next = NULL; sn = dkstr_rchr(cmd->current_name, fn_sep[0]); if(!sn) sn = cmd->current_name; st = dkstat_open(cmd->current_name); if(st) { back = 1; ft = dkstat_filetype(st); if(cmd->show_summary) { double x; math_err = 0; switch((ft) & (~(DK_FT_SYMLINK))) { case DK_FT_REG: { xul = dkstat_size_ok(st, &math_err); old_err = cmd->me_ull_bytes_found; if(math_err) { cmd->me_ull_bytes_found = math_err; } x = dkma_ull_to_double(xul); cmd->bytes_found = dkma_add_double_ok( cmd->bytes_found, x, &math_err ); cmd->ull_bytes_found = dkma_add_ull_ok( cmd->ull_bytes_found, xul, &(cmd->me_ull_bytes_found) ); if((cmd->me_ull_bytes_found) && (!old_err)) { /* ##### ERROR: size exceeds range */ back = 0; } old_err = cmd->me_ull_bytes_in_files; if(math_err) { cmd->me_ull_bytes_in_files = math_err; } cmd->bytes_in_files = dkma_add_double_ok( cmd->bytes_in_files, x, &math_err ); cmd->ull_bytes_in_files = dkma_add_ull_ok( cmd->ull_bytes_in_files, xul, &(cmd->me_ull_bytes_in_files) ); if((cmd->me_ull_bytes_in_files) && (!old_err)) { /* ##### ERROR: size exceeds range */ back = 0; } cmd->files_found = dkma_add_double_ok( cmd->files_found, 1.0, &math_err ); if(cmd->ull_files_found == DK_MAX_LONG_LONG_UNSIGNED) { cmd->me_ull_files_found = DK_ERR_MATH_OOR; } else { cmd->ull_files_found += DK_ONE_LONG_LONG_UNSIGNED; } } break; case DK_FT_DIR: { xul = dkstat_size_ok(st, &math_err); old_err = cmd->me_ull_bytes_found; if(math_err) { cmd->me_ull_bytes_found = math_err ; } cmd->ull_bytes_found = dkma_add_ull_ok( cmd->ull_bytes_found, xul, &(cmd->me_ull_bytes_found) ); cmd->bytes_found = dkma_add_double_ok( cmd->bytes_found, dkma_ull_to_double(xul), &math_err ); if((cmd->me_ull_bytes_found) && (!old_err)) { /* ##### ERROR: size exceeds range */ back = 0; } old_err = cmd->me_ull_dirs_found; if(cmd->ull_dirs_found == DK_MAX_LONG_LONG_UNSIGNED) { cmd->me_ull_dirs_found = DK_ERR_MATH_OOR; } else { cmd->ull_dirs_found += DK_ONE_LONG_LONG_UNSIGNED; } cmd->dirs_found = dkma_add_double_ok( cmd->dirs_found, 1.0, &math_err ); if((cmd->me_ull_dirs_found) && (!old_err)) { /* ERROR: size exceeds range */ back = 0; } } break; } if(math_err) { cmd->math_error = 1; back = 0; } } if((ft & (~(DK_FT_SYMLINK))) == DK_FT_DIR) { /* directory */ if(must_go_sub(cmd, NULL, st)) { current = dir_entry_new(cmd->current_name, NULL); if(current) { if(ft & DK_FT_SYMLINK) { current->ll = 1UL; } while(current) { if((dnt = dkdir_next(current->dir))) { if(dnt == 1) { if((!(cmd->stay_on_filesystem)) || (dkstat_device(current->st) == dkdir_device(current->dir))) { char *xxshn; xxshn = dkdir_get_shortname(current->dir); if(strcmp(xxshn, ".") && strcmp(xxshn, "..")) { if(cmd->sz_wanted) { math_err = 0; switch((dkdir_filetype(current->dir)) & (~(DK_FT_SYMLINK))) { case DK_FT_REG: { math_err = 0; old_err = cmd->me_ull_bytes_found; xul = dkdir_size_ok(current->dir, &math_err); if(math_err) { cmd->me_ull_bytes_found = math_err; } current->ull_bytes_found = dkma_add_ull_ok( current->ull_bytes_found, xul, &(cmd->me_ull_bytes_found) ); if((cmd->me_ull_bytes_found) && (!old_err)) { /* ##### ERROR: size exceeds range */ back = 0; } current->bytes_found = dkma_add_double_ok( current->bytes_found, dkma_ull_to_double(xul), &math_err ); } break; } if(math_err) { cmd->math_error = 1; } } if(cmd->show_summary) { double x; math_err = 0; switch((dkdir_filetype(current->dir)) & (~(DK_FT_SYMLINK))) { case DK_FT_REG: { xul = dkdir_size_ok(current->dir, &math_err); x = dkma_ull_to_double(xul); old_err = cmd->me_ull_bytes_found; if(math_err) { cmd->me_ull_bytes_found = math_err; cmd->me_ull_bytes_in_files = math_err; } cmd->ull_bytes_found = dkma_add_ull_ok( cmd->ull_bytes_found, xul, &(cmd->me_ull_bytes_found) ); cmd->bytes_found = dkma_add_double_ok( cmd->bytes_found, x, &math_err ); if((cmd->me_ull_bytes_found) && (!old_err)) { /* ##### ERROR: size exceeds range */ back = 0; } cmd->ull_bytes_in_files = dkma_add_ull_ok( cmd->ull_bytes_in_files, xul, &(cmd->me_ull_bytes_in_files) ); cmd->bytes_in_files = dkma_add_double_ok( cmd->bytes_in_files, x, &math_err ); if(cmd->ull_files_found == DK_MAX_LONG_LONG_UNSIGNED) { cmd->me_ull_files_found = DK_ERR_MATH_OOR; } else { cmd->ull_files_found += DK_ONE_LONG_LONG_UNSIGNED; } cmd->files_found = dkma_add_double_ok( cmd->files_found, 1.0, &math_err ); } break; case DK_FT_DIR: { xul = dkdir_size_ok(current->dir, &math_err); old_err = cmd->me_ull_bytes_found; if(math_err) { cmd->me_ull_bytes_found = math_err; } cmd->ull_bytes_found = dkma_add_ull_ok( cmd->ull_bytes_found, xul, &(cmd->me_ull_bytes_found) ); cmd->bytes_found = dkma_add_double_ok( cmd->bytes_found, dkma_ull_to_double(xul), &math_err ); if((cmd->me_ull_bytes_found) && (!old_err)) { /* ##### ERROR: size exceeds range */ back = 0; } if(cmd->ull_dirs_found == DK_MAX_LONG_LONG_UNSIGNED) { cmd->me_ull_dirs_found = DK_ERR_MATH_OOR; } else { cmd->ull_dirs_found += DK_ONE_LONG_LONG_UNSIGNED; } cmd->dirs_found = dkma_add_double_ok( cmd->dirs_found, 1.0, &math_err ); } break; } if(math_err) { cmd->math_error = 1; back = 0; } } } current->fn = dkdir_get_fullname(current->dir); if(current->fn) { current->sn = dkdir_get_shortname(current->dir); if(strcmp(current->sn, ".") && strcmp(current->sn, "..")) { current->testst = dkdir_stat(current->dir); current->ft = dkstat_filetype(current->testst); if(((current->ft) & (~(DK_FT_SYMLINK))) == DK_FT_DIR) { if(must_go_sub(cmd, current, current->testst)) { current = dir_entry_new(current->fn, current); if(current) { if(((current->prev)->ft) & DK_FT_SYMLINK) { current->ll += 1UL; } } else { logmsgs[0] = kls_str[0]; logmsgs[1] = current->fn; logmsgs[2] = kls_str[1]; dkapp_log_msg( app, DK_LOG_LEVEL_ERROR, logmsgs, 3 ); /* ERROR: Failed to create traversal struct */ back = 0; } } else { if(output_check(cmd,current,0)) { output_for_entry( cmd, NULL, current->testst, current->fn ); } } } else { if(output_check(cmd,current,0)) { output_for_entry( cmd, NULL, current->testst, current->fn ); } } } } } } else { } } else { /* go up one directory */ if(cmd->sz_wanted) { math_err = 0; xul = dkstat_size_ok(current->st, &math_err); old_err = current->ull_math_error; current->ull_bytes_found = dkma_add_ull_ok( current->ull_bytes_found, xul, &(current->ull_math_error) ); current->bytes_found = dkma_add_double_ok( current->bytes_found, dkma_ull_to_double(xul), &math_err ); if((current->ull_math_error) && (!old_err)) { /* ##### ERROR: size exceeds range */ back = 0; } if(math_err) { cmd->math_error = 1; } } if(output_check(cmd,current,1)) { output_for_entry( cmd, current, current->st, current->name ); } next = current->prev; if(next) { if(cmd->sz_wanted) { math_err = 0; next->ull_bytes_found = dkma_add_ull_ok( next->ull_bytes_found, current->ull_bytes_found, &(next->ull_math_error) ); if(current->ull_math_error) { next->ull_math_error = current->ull_math_error; } next->bytes_found = dkma_add_double_ok( next->bytes_found, current->bytes_found, &math_err ); if(math_err) { cmd->math_error = 1; back = 0; } } } current->testst = NULL; dkdir_close(current->dir); dkstat_close(current->st); cptr = current->name; dk_delete(cptr); current->dir = NULL; current->st = NULL; current->name = NULL; current->prev = NULL; current->ll = 0UL; dk_delete(current); current = next; } } } else { logmsgs[0] = kls_str[0]; logmsgs[1] = cmd->current_name; logmsgs[2] = kls_str[1]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsgs, 3); /* ERROR: Failed to create traversal structure */ back = 0; } } else { output_for_entry(cmd, NULL, st, cmd->current_name); } } else { /* no directory */ output_for_entry(cmd, NULL, st, cmd->current_name); } dkstat_close(st); st = NULL; } else { logmsgs[0] = kls_str[2]; logmsgs[1] = cmd->current_name; logmsgs[2] = kls_str[3]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsgs, 3); /* ERROR: stat failed for name */ back = 0; } return back; } /** Find output width for size. @param cmd kls job. */ static void adjust_cmd_size_output_width DK_P1(KlsCmd *,cmd) { char buffer[32], *stptr; size_t max, sz; max = 0; sprintf(buffer, "%20.0lf", cmd->dirs_found); stptr = dkstr_start(buffer, NULL); if(stptr) { sz = strlen(stptr); if(sz > max) max = sz; } sprintf(buffer, "%20.0lf", cmd->files_found); stptr = dkstr_start(buffer, NULL); if(stptr) { sz = strlen(stptr); if(sz > max) max = sz; } sprintf(buffer, "%20.0lf", cmd->bytes_in_files); stptr = dkstr_start(buffer, NULL); if(stptr) { sz = strlen(stptr); if(sz > max) max = sz; } sprintf(buffer, "%20.0lf", cmd->bytes_found); stptr = dkstr_start(buffer, NULL); if(stptr) { sz = strlen(stptr); if(sz > max) max = sz; } max++; cmd->size_output_width = max; } /** Run for the given command. @param cmd Kls job. @return 1 on success, 0 on error. */ static int run_for_cmd DK_P1(KlsCmd *,cmd) { int back = 0; size_t maxpathlen; int i, need_fne; dk_fne_t *fne; char *fn, *cptr; char *logmsgs[8]; #if (DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H) if(cmd->print_list) { cptr = strchr((cmd->print_list), 'x'); if(cptr) { cmd->md5_wanted = 1; } } #endif if(cmd->print_list) { cptr = strchr((cmd->print_list), 's'); if(cptr) { cmd->sz_wanted = 1; } } if(cmd->file_types) { cptr = cmd->file_types; while(*cptr) { switch(*cptr) { case 'f' : cmd->ft_reg = 1; break; case 'd' : cmd->ft_dir = 1; break; case 'p' : cmd->ft_pipe = 1; break; case 'c' : cmd->ft_chr = 1; break; case 'b' : cmd->ft_blk = 1; break; case 's' : cmd->ft_sock = 1; break; case 'o' : cmd->ft_oth = 1; break; } cptr++; } } else { cmd->ft_reg = 1; cmd->ft_dir = 1; } if((cmd->names_used) == 0) { maxpathlen = dksf_get_maxpathlen(); fn = dk_new(char,maxpathlen); if(fn) { if(dksf_getcwd(fn,maxpathlen)) { cmd->current_name = fn; cmd->current_depth = 0UL; cmd->current_symlinks = 0UL; cmd->remove_cwd_from_name = 1; /* cmd->remove_cwd_length = strlen(fn) + 1; */ cmd->remove_cwd_length = strlen(fn); if((cmd->remove_cwd_length) > 0) { if(fn[(cmd->remove_cwd_length) - 1] != fn_sep[0]) { cmd->remove_cwd_length += 1; } } cmd->dc_dir = 0; cmd->dc_contents = 1; back = run_for_current(cmd); } else { logmsgs[0] = kls_str[4]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsgs, 1); /* ERROR: Failed to estimate current directory */ } dk_delete(fn); } else { logmsgs[0] = kls_str[5]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsgs, 1); /* ERROR: Not enough memory for current directory */ } } else { back = 1; for(i = 0; i < (cmd->names_used); i++) { dksf_correct_fnsep( (cmd->filenames)[i] ); need_fne = dksf_must_expand_filename( (cmd->filenames)[i] ); if(need_fne) { fne = dkfne_open(((cmd->filenames)[i]), 1, 1); if(fne) { while(dkfne_next(fne)) { fn = dkfne_get_fullname(fne); if(fn) { cmd->current_name = fn; cmd->current_depth = 0UL; cmd->current_symlinks = 0UL; if(!run_for_current(cmd)) { back = 0; } } else { logmsgs[0] = kls_str[6]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsgs, 1); /* ERROR: Failed to find full name */ back = 0; } } dkfne_close(fne); } else { logmsgs[0] = kls_str[7]; logmsgs[1] = (cmd->filenames)[i]; logmsgs[2] = kls_str[8]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsgs, 3); /* ERROR: Failed to open FNE */ back = 0; } } else { cmd->current_name = (cmd->filenames)[i]; cmd->current_depth = 0UL; cmd->current_symlinks = 0UL; if(!run_for_current(cmd)) { back = 0; } } } } if(cmd->show_summary) { adjust_cmd_size_output_width(cmd); fputs(kls_str[9], cmd->output_file); pr_ull_or_double( cmd, cmd->ull_dirs_found, cmd->dirs_found, cmd->me_ull_dirs_found ); fputc('\n', cmd->output_file); fputs(kls_str[10], cmd->output_file); pr_ull_or_double( cmd, cmd->ull_files_found, cmd->files_found, cmd->me_ull_files_found ); fputc('\n', cmd->output_file); fputs(kls_str[11], cmd->output_file); pr_ull_or_double( cmd, cmd->ull_bytes_in_files, cmd->bytes_in_files, cmd->me_ull_bytes_in_files ); fputc('\n', cmd->output_file); fputs(kls_str[12], cmd->output_file); pr_ull_or_double( cmd, cmd->ull_bytes_found, cmd->bytes_found, cmd->me_ull_bytes_found ); fputc('\n', cmd->output_file); } return back; } /** Get string length on screen. @param cmd Kls job. @param max Maximum screen space already used. @param str String to print. @return Maximum of old screen space and string length on screen. */ static size_t test_string_length DK_P3(KlsCmd *,cmd, size_t, max, char *, str) { size_t back, x; back = max; if(str) { x = dkapp_prlen(app, str); if(x > back) back = x; } return back; } /** Print a string right aligned. @param str String to print. @param max Available place on screen. */ static void print_string_right_aligned DK_P2(char *,str, size_t, max) { size_t sz, i; if(str) { sz = dkapp_prlen(app, str); for(i = sz; i < max; i++) fputc(' ', stdout); dkapp_stdout(app, str); } else { for(i = 0; i < max; i++) fputc(' ', stdout); } } /** Three spaces are used before and after the value. */ static char three_spaces[] = { " " }; /** Show one configuration setting. @param max Maximu screen space. @param str Option to show. */ static void show_info_type DK_P2(size_t, max, char *,str) { size_t i; fputs(&(three_spaces[1]), stdout); fputs(three_spaces, stdout); fputs(three_spaces, stdout); for(i = 0; i < max; i++) fputc(' ', stdout); dkapp_stdout(app, str); fputc('\n', stdout); } /** Show configuration. @param cmd Kls job. */ static void show_conf DK_P1(KlsCmd *,cmd) { size_t max; char ldbuffer[32], *chrptr; sprintf(ldbuffer, "%lu", cmd->symlinks_allowed); max = 0; chrptr = kls_str[46]; if(cmd->symlinks_limited) chrptr = ldbuffer; max = test_string_length(cmd, max, chrptr); sprintf(ldbuffer, "%d", cmd->size_output_width); chrptr = ldbuffer; max = test_string_length(cmd, max, kls_str[44]); max = test_string_length(cmd, max, kls_str[45]); if(cmd->size_output_width == -1) chrptr = kls_str[46]; if(cmd->size_output_width == 0) chrptr = kls_str[54]; max = test_string_length(cmd, max, chrptr); max = test_string_length(cmd, max, kls_str[50]); max = test_string_length(cmd, max, digest_types[0]); max = test_string_length(cmd, max, digest_types[1]); max = test_string_length(cmd, max, digest_encodings[cmd->message_digest_encoding]); max = test_string_length(cmd, max, cmd->file_types); max = test_string_length(cmd, max, cmd->print_list); dkapp_stdout(app, kls_str[51]); fputc('\n', stdout); if(cmd->print_list) { dkapp_stdout(app, "-p"); dkapp_stdout(app, three_spaces); print_string_right_aligned(cmd->print_list, max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[17]); fputc('\n', stdout); chrptr = cmd->print_list; while(*chrptr) { switch(*chrptr) { case 'n': show_info_type(max, kls_str[18]); break; case 's': show_info_type(max, kls_str[19]); break; case 't': show_info_type(max, kls_str[20]); break; case 'p': show_info_type(max, kls_str[21]); break; case 'x': show_info_type(max, kls_str[22]); break; case 'l': show_info_type(max, kls_str[23]); break; case 'c': show_info_type(max, kls_str[24]); break; case 'm': show_info_type(max, kls_str[25]); break; case 'a': show_info_type(max, kls_str[26]); break; case 'u': show_info_type(max, kls_str[27]); break; case 'g': show_info_type(max, kls_str[28]); break; case 'd': show_info_type(max, kls_str[29]); break; case 'r': show_info_type(max, kls_str[30]); break; case 'i': show_info_type(max, kls_str[31]); break; } chrptr++; } } dkapp_stdout(app, "-m"); dkapp_stdout(app, three_spaces); print_string_right_aligned(digest_types[cmd->message_digest_type], max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[32]); fputc('\n', stdout); dkapp_stdout(app, "-e"); dkapp_stdout(app, three_spaces); print_string_right_aligned( digest_encodings[cmd->message_digest_encoding], max ); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[55]); fputc('\n', stdout); dkapp_stdout(app, "-r"); dkapp_stdout(app, three_spaces); print_string_right_aligned(((cmd->rec)?(kls_str[44]):(kls_str[45])), max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[33]); fputc('\n', stdout); if(cmd->file_types) { dkapp_stdout(app, "-t"); dkapp_stdout(app, three_spaces); print_string_right_aligned(cmd->file_types, max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[34]); fputc('\n', stdout); chrptr = cmd->file_types; while(*chrptr) { switch(*chrptr) { case 'f': show_info_type(max, kls_str[35]); break; case 'd': show_info_type(max, kls_str[36]); break; case 'p': show_info_type(max, kls_str[37]); break; case 'c': show_info_type(max, kls_str[38]); break; case 'b': show_info_type(max, kls_str[39]); break; case 's': show_info_type(max, kls_str[40]); break; case 'o': show_info_type(max, kls_str[41]); break; } chrptr++; } } dkapp_stdout(app, "-d"); dkapp_stdout(app, three_spaces); ldbuffer[0]=ldbuffer[1]=ldbuffer[2]='\0'; if(cmd->dc_dir) { if(cmd->dc_contents) { ldbuffer[0] = 'd'; ldbuffer[1]='c'; } else { ldbuffer[0] = 'd'; } } else { if(cmd->dc_contents) { ldbuffer[0]='c'; } else { ldbuffer[0] = 'd'; ldbuffer[1]='c'; } } print_string_right_aligned(ldbuffer, max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[47]); fputc('\n', stdout); chrptr = ldbuffer; while(*chrptr) { switch(*chrptr) { case 'd': show_info_type(max, kls_str[48]); break; case 'c': show_info_type(max, kls_str[49]); break; } chrptr++; } sprintf(ldbuffer, "%lu", cmd->symlinks_allowed); chrptr = kls_str[46]; if(cmd->symlinks_limited) chrptr = ldbuffer; dkapp_stdout(app, "-l"); dkapp_stdout(app, three_spaces); print_string_right_aligned(chrptr, max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[42]); fputc('\n', stdout); sprintf(ldbuffer, "%d", cmd->size_output_width); chrptr = ldbuffer; if(cmd->size_output_width == -1) chrptr = kls_str[46]; if(cmd->size_output_width == 0) chrptr = kls_str[54]; dkapp_stdout(app, "-w"); dkapp_stdout(app, three_spaces); print_string_right_aligned(chrptr, max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[53]); fputc('\n', stdout); dkapp_stdout(app, "-f"); dkapp_stdout(app, three_spaces); print_string_right_aligned(((cmd->stay_on_filesystem)?(kls_str[44]):(kls_str[45])),max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[52]); fputc('\n', stdout); dkapp_stdout(app, "-s"); dkapp_stdout(app, three_spaces); print_string_right_aligned(((cmd->show_summary)?(kls_str[44]):(kls_str[45])),max); dkapp_stdout(app, three_spaces); dkapp_stdout(app, kls_str[43]); fputc('\n', stdout); } /** Long option keywords. */ static char *long_options_keywords[] = { /* 00 */ "m$essage-digest", /* 01 */ "o$utputfile", /* 02 */ "p$rint", /* 03 */ "w$idth", /* 04 */ "r$ecursive", /* 05 */ "t$ype", /* 06 */ "c$onfigure", /* 07 */ "l$inks", /* 08 */ "u$nconfigure", /* 09 */ "d$irectory", /* 10 */ "su$mmary", /* 11 */ "v$ersion", /* 12 */ "h$elp", /* 13 */ "sh$ow-configuration", /* 14 */ "st$ay-on-filesystem", /* 15 */ "e$ncoding", NULL }; /** Main program after creating the application. @param argc Number of command line arguments. @param argv Command line arguments array. @return 1 on success, 0 on error. */ static int run_main(int argc, char **argv) { int back = 0; PCHAR *filenames; KlsCmd cmd; char *outputname, *cptr; FILE *outputfile; int i, lfd; char **argptr, **licptr; char *my_info, *my_types; char *logmsgs[8]; outputfile = NULL; my_info = NULL; my_types = NULL; filenames = dk_new(PCHAR,argc); if(filenames) { for(i = 0; i < argc; i++) { filenames[i] = NULL; } cmd_init(&cmd); cmd.filenames = filenames; cmd.names_used = 0; /* Use cmd line arguments */ argptr = argv; argptr++; lfd = 1; while(lfd < argc) { cptr = *argptr; if(cptr) { if(*cptr == '-') { cptr++; switch(*cptr) { case '-' : { int found; char *optarg; found = -1; /* option not found yet */ cptr++; /* move to start of keyword */ optarg = NULL; /* no argument found yet */ optarg = dkstr_chr(cptr, '='); if(optarg) { *(optarg++) = '\0'; } found = dkstr_array_abbr(long_options_keywords, cptr, '$', 1); if(found > -1) { switch(found) { case 0: { /* message digest type */ cmd.mdtype_configured = 1; cmd.message_digest_type = -1; if(optarg) { cmd.message_digest_type = dkstr_array_index( digest_types, optarg, 0 ); } if(cmd.message_digest_type < 0) cmd.message_digest_type = MD_TYPE_SHA1; } break; case 1: { /* output file name */ if(optarg) { outputfile = dkapp_fopen(app, optarg, "w"); if(outputfile) { if(cmd.output_file) { fclose(cmd.output_file); cmd.output_file = NULL; } cmd.output_file = outputfile; } } } break; case 2: { /* print order */ if(optarg) { cmd.print_list = optarg; } } break; case 3: { /* size output width */ if(optarg) { int i; cmd.size_output_configured = 1; if(sscanf(optarg, "%d", &i) == 1) { if(i < -1) i = -1; if(i > 20) i = 20; cmd.size_output_width = i; } else { cmd.size_output_width = -1; } } else { cmd.size_output_configured = 0; } } break; case 4: { /* recursive */ cmd.rec_configured = 1; if(optarg) { cmd.rec = dkstr_is_on(optarg); } else { cmd.rec = 1; } } break; case 5: { /* types */ if(optarg) { cmd.file_types = optarg; } else { cmd.file_types = NULL; } } break; case 6: { /* configure */ if(optarg) { cmd.configure_only = dkstr_is_on(optarg); } else { cmd.configure_only = 1; } } break; case 7: { /* symlink level */ unsigned long x; cmd.symlinks_configured = 1; if(optarg) { if(sscanf(optarg, "%lu", &x) == 1) { cmd.symlinks_limited = 1; cmd.symlinks_allowed = x; } else { cmd.symlinks_limited = 0; cmd.symlinks_allowed = 1UL; } } else { cmd.symlinks_limited = 0; cmd.symlinks_allowed = 1UL; } } break; case 8: { /* unconfigure */ if(optarg) { if(dkstr_is_on(optarg)) { cmd.configure_only = 1; cmd.unconf_only = 1; dkapp_unconfigure(app); } } else { cmd.configure_only = 1; cmd.unconf_only = 1; dkapp_unconfigure(app); } } break; case 9: { /* directory handling */ cmd.dc_configured = 1; if(optarg) { cptr = optarg ; while(*cptr) { switch(*cptr) { case 'd': cmd.dc_dir = 1; break; case 'c': cmd.dc_contents = 1; break; } cptr++; } } else { cmd.dc_contents = 1; cmd.dc_dir = 0; } } break; case 10: { /* summary */ cmd.summary_configured = 1; if(optarg) { cmd.show_summary = dkstr_is_on(optarg); } else { cmd.show_summary = 1; } } break; case 11: { /* version */ cmd.show_version = 1; if(optarg) cmd.show_version = dkstr_is_on(optarg); } break; case 12: { /* help */ cmd.show_help = 1; if(optarg) cmd.show_help = dkstr_is_on(optarg); } break; case 13: { /* show configuration */ cmd.show_configuration = 1; if(optarg) cmd.show_configuration = dkstr_is_on(optarg); } break; case 14: { /* stay on filesystem */ cmd.stay_configured = 1; cmd.stay_on_filesystem = 1; if(optarg) cmd.stay_on_filesystem = dkstr_is_on(optarg); } break; case 15: { /* encoding */ cmd.mdenc_configured = 1; cmd.message_digest_encoding = -1; if(optarg) { cmd.message_digest_encoding = dkstr_array_index( digest_encodings, optarg, 0 ); } if(cmd.message_digest_encoding < 0) { cmd.message_digest_encoding = MD_ENC_HEX; } } break; } } } break; case 'o' : { /* output file name */ outputname = NULL; cptr++; if(*cptr) { outputname = cptr; } else { lfd++; argptr++; if(lfd < argc) { outputname = *argptr; } } if(outputname) { dk_fne_t *ofne; char *ofnptr; dksf_correct_fnsep(outputname); if(dksf_must_expand_filename(outputname)) { ofne = dkfne_open(outputname, 1, 0); if(ofne) { ofnptr = dkapp_fne_one(app, ofne, outputname); if(ofnptr) { outputfile = dkapp_fopen(app, ofnptr, "w"); if(outputfile) { if(cmd.output_file) { fclose(cmd.output_file); cmd.output_file = NULL; } cmd.output_file = outputfile; } dk_delete(ofnptr); } dkfne_close(ofne); ofne = NULL; } else { dkapp_err_memory(app, sizeof(dk_fne_t), 1); } } else { outputfile = dkapp_fopen(app,outputname,"w"); if(outputfile) { if(cmd.output_file) { fclose(cmd.output_file); cmd.output_file = NULL; } cmd.output_file = outputfile; } } } } break; case 'u' : { cmd.configure_only = 1; cmd.unconf_only = 1; dkapp_unconfigure(app); } break; case 'f' : { cmd.stay_on_filesystem = 1; cmd.stay_configured = 1; } break; case 'p' : { /* print info list */ cptr++; outputname = NULL; if(*cptr) { outputname = cptr; } else { lfd++; argptr++; if(lfd < argc) { outputname = *argptr; } } if(outputname) { cmd.print_list = outputname; } } break; case 'r' : { /* recursively */ cmd.rec_configured = 1; if(cptr[1] == '-') { cmd.rec = 0; } else { cmd.rec = 1; } } break; case 't' : { /* file types to list */ cptr++; outputname = NULL; if(*cptr) { outputname = cptr; } else { lfd++; argptr++; if(lfd < argc) { outputname = *argptr; } } if(outputname) { cmd.file_types = outputname; } } break; case 'c' : { /* write configuration */ cmd.configure_only = 1; } break; case 'd' : { outputname = NULL; cptr++; if(*cptr) { outputname = cptr; } else { lfd++; argptr++; if(lfd < argc) { outputname = *argptr; } } if(outputname) { cmd.dc_configured = 1; while(*outputname) { switch(*outputname) { case 'd': cmd.dc_dir = 1; break; case 'c': cmd.dc_contents = 1; break; } outputname++; } } } break; case 'm' : { outputname = NULL; cptr++; if(*cptr) { outputname = cptr; } else { lfd++; argptr++; if(lfd < argc) { outputname = *argptr; } } if(outputname) { cmd.message_digest_type = dkstr_array_index( digest_types, outputname, 0 ); if(cmd.message_digest_type < 0) { cmd.message_digest_type = MD_TYPE_SHA1; } else { cmd.mdtype_configured = 1; } } } break; case 'e' : { outputname = NULL; cptr++; if(*cptr) { outputname = cptr; } else { lfd++; argptr++; if(lfd < argc) { outputname = *argptr; } } if(outputname) { cmd.message_digest_encoding = dkstr_array_index( digest_encodings, outputname, 0 ); if(cmd.message_digest_encoding < 0) { cmd.message_digest_encoding = MD_ENC_HEX; } else { cmd.mdenc_configured = 1; } } } break; case 'l' : { /* symlink depth */ outputname = NULL; cptr++; if(*cptr) { outputname = cptr; } else { lfd++; argptr++; if(lfd < argc) { outputname = *argptr; } } if(outputname) { unsigned long x; if(sscanf(outputname, "%lu", &x) == 1) { cmd.symlinks_allowed = x; cmd.symlinks_limited = 1; cmd.symlinks_configured = 1; } else { cmd.symlinks_configured = 1; cmd.symlinks_limited = 0; } } } break; case 'w' : { /* size column width */ outputname = NULL; cptr++; if(*cptr) { outputname = cptr; } else { lfd++; argptr++; if(lfd < argc) { outputname = *argptr; } } if(outputname) { int x; if(sscanf(outputname, "%d", &x) == 1) { if(x < -1) { x = -1; } if(x > 20) { x = 20; } cmd.size_output_width = x; cmd.size_output_configured = 1; } } } break; case 's' : { /* show summary */ cmd.summary_configured = 1; if(cptr[1] == '-') { cmd.show_summary = 0; } else { cmd.show_summary = 1; } } break; case 'v' : { /* print version */ if(cptr[1] == '-') { cmd.show_version = 0; } else { cmd.show_version = 1; } } break; case 'h' : { /* print help */ if(cptr[1] == '-') { cmd.show_help = 0; } else { cmd.show_help = 1; } } break; case 'C' : { if(cptr[1] == '-') { cmd.show_configuration = 0; } else { cmd.show_configuration = 1; } } break; } } else { filenames[cmd.names_used] = cptr; cmd.names_used += 1; } } lfd++; argptr++; } if(!(cmd.output_file)) { cmd.output_file = stdout; } /* Complete configuration from preferences */ complete_from_prefs(&cmd, &my_info, &my_types); /* Complete configuration by use of built-in defaults */ if(!(cmd.print_list)) { cmd.print_list = default_print_list; } if(!(cmd.file_types)) { cmd.file_types = default_file_types; } cmd.rec_configured = 1; cmd.symlinks_configured = 1; cmd.summary_configured = 1; if(!(cmd.dc_configured)) { cmd.dc_configured = 1; cmd.dc_contents = 1; cmd.dc_dir = 0; } if(!((cmd.dc_dir) || (cmd.dc_contents))) { cmd.dc_contents = 1; } /* Run */ if(cmd.configure_only) { if(!(cmd.unconf_only)) { char osbuffer[16]; char dcbuffer[3]; char slbuffer[32]; slbuffer[0] = '\0'; if(cmd.print_list) { dkapp_set_pref(app, pn_print_list, cmd.print_list); } sprintf(osbuffer, "%d", cmd.size_output_width); dkapp_set_pref(app, pn_width, osbuffer); dkapp_set_pref(app, pn_digest, digest_types[cmd.message_digest_type]); dkapp_set_pref(app, pn_mdenc, digest_encodings[cmd.message_digest_encoding]); dkapp_set_pref(app, pn_rec, ((cmd.rec) ? pv_on : pv_off)); if(cmd.symlinks_limited) { sprintf(slbuffer, "%lu", cmd.symlinks_allowed); dkapp_set_pref(app, pn_links, slbuffer); } else { dkapp_set_pref(app, pn_links, pv_unlimited); } dkapp_set_pref(app, pn_summary, ((cmd.show_summary) ? pv_on : pv_off)); if(cmd.file_types) { dkapp_set_pref(app, pn_type, cmd.file_types); } dkapp_set_pref(app,pn_stay,((cmd.stay_on_filesystem) ? pv_on : pv_off)); dcbuffer[0] = dcbuffer[1] = '-'; dcbuffer[2] = '\0'; if(cmd.dc_dir) { dcbuffer[0] = 'd'; } if(cmd.dc_contents) { dcbuffer[1] = 'c'; } dkapp_set_pref(app, pn_dir, dcbuffer); show_conf(&cmd); } back = 1; } else { if((cmd.show_help) || (cmd.show_version) ||(cmd.show_configuration)) { if(cmd.show_version) { printf("\n"); print_version(); #if DK_HAVE_OPENSSL_MD5_H || DK_HAVE_OPENSSL_SHA_H || DK_HAVE_OPENSSL_RIPEMD_H printf("\n"); licptr = openssl_lib_version; while(*licptr) { printf("%s\n", *(licptr++)); } #endif printf("\n"); } if(cmd.show_help) { dkapp_help(app, "kls.txt", help_text); } if(cmd.show_configuration) { /* ##### show the configuration */ show_conf(&cmd); } back = 1; } else { back = run_for_cmd(&cmd); } } /* Free the filenames */ if(my_info) { dk_delete(my_info); my_info = NULL; } if(my_types) { dk_delete(my_types); my_types = NULL; } if(outputfile) { fclose(outputfile); outputfile = NULL; } for(i = 0; i < argc; i++) { filenames[i] = NULL; } dk_delete(filenames); } else { logmsgs[0] = kls_str[5]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsgs, 1); /* ERROR: Not enough memory to store filenames */ } return back; } /** The main() function of the kls program. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, any other value indicates an error. */ int main(int argc, char *argv[]) { int exval = 0; int xargc; char **xargv; #line 3451 "kls.ctr" allocated_print_list = NULL; allocated_dc = NULL; app = dkapp_open_ext1(argc, argv, packagename, sysconfdir, 0, 0); if(app) { xargc = dkapp_get_argc(app); xargv = dkapp_get_argv(app); dkapp_find_multi(app, kls_mesgs, "kls" ); exval = run_main(xargc, xargv); dkapp_close(app); app = NULL; } else { if(!dkapp_silence_check(argc,argv)) { fprintf(stderr, "ERROR: NOT ENOUGH MEMORY\n"); fflush(stderr); } } if(allocated_print_list) { dk_delete(allocated_print_list); allocated_print_list = NULL; } if(allocated_dc) { dk_delete(allocated_dc); allocated_dc = NULL; } exval = (exval ? 0 : 1); #line 3477 "kls.ctr" exit(exval); return exval; }