"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-filename.c" (15 Mar 2019, 11302 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-filename.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.52_vs_0.09.54.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 #define STRESS_FILENAME_PROBE   (0) /* Default */
   28 #define STRESS_FILENAME_POSIX   (1) /* POSIX 2008.1 */
   29 #define STRESS_FILENAME_EXT (2) /* EXT* filesystems */
   30 
   31 typedef struct {
   32     const uint8_t opt;
   33     const char *opt_text;
   34 } filename_opts_t;
   35 
   36 static const filename_opts_t filename_opts[] = {
   37     { STRESS_FILENAME_PROBE,    "probe" },
   38     { STRESS_FILENAME_POSIX,    "posix" },
   39     { STRESS_FILENAME_EXT,      "ext" },
   40     { -1,               NULL }
   41 };
   42 
   43 /* Allowed filename characters */
   44 static char allowed[256];
   45 
   46 /*
   47  * The Open Group Base Specifications Issue 7
   48  * POSIX.1-2008, 3.278 Portable Filename Character Set
   49  */
   50 static char posix_allowed[] =
   51     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   52     "abcdefghijklmnopqrstuvwxyz"
   53     "0123456789._-";
   54 
   55 int stress_set_filename_opts(const char *opt)
   56 {
   57     size_t i;
   58 
   59     for (i = 0; filename_opts[i].opt_text; i++) {
   60         if (!strcmp(opt, filename_opts[i].opt_text)) {
   61             uint8_t filename_opt = filename_opts[i].opt;
   62             set_setting("filename-opts", TYPE_ID_UINT8, &filename_opt);
   63             return 0;
   64         }
   65     }
   66     (void)fprintf(stderr, "filename-opts option '%s' not known, options are:", opt);
   67     for (i = 0; filename_opts[i].opt_text; i++)
   68         (void)fprintf(stderr, "%s %s",
   69             i == 0 ? "" : ",", filename_opts[i].opt_text);
   70     (void)fprintf(stderr, "\n");
   71     return -1;
   72 }
   73 
   74 /*
   75  *  stress_filename_probe()
   76  *  determine allowed filename chars by probing
   77  */
   78 static int stress_filename_probe(
   79     const args_t *args,
   80     char *filename,
   81     char *ptr,
   82     size_t *chars_allowed)
   83 {
   84     size_t i, j;
   85 
   86     /*
   87      *  Determine allowed char set for filenames
   88      */
   89     for (j = 0, i = 0; i < 256; i++) {
   90         size_t k;
   91         int fd;
   92 
   93         if ((i == 0) || (i == '/'))
   94             continue;
   95 #if defined(__APPLE__)
   96         if (i == ':')
   97             continue;
   98 #endif
   99         /*
  100          *  Some systems such as Windows need long file
  101          *  names of around 64 chars with invalid probe
  102          *  chars to be able to be detect for bad chars.
  103          *  Not sure why that is.
  104          */
  105         for (k = 0; k < 64; k++)
  106             *(ptr + k) = i;
  107         *(ptr + k) = '\0';
  108 
  109         if ((fd = creat(filename, S_IRUSR | S_IWUSR)) < 0) {
  110             /*
  111              *  We only expect EINVAL on bad filenames,
  112              *  and WSL on Windows 10 can return ENOENT
  113              */
  114             if ((errno != EINVAL) && (errno != ENOENT)) {
  115                 pr_err("%s: creat() failed when probing "
  116                     "for allowed filename characters, "
  117                     "errno = %d (%s)\n",
  118                     args->name, errno, strerror(errno));
  119                 pr_inf("%s: perhaps retry and use "
  120                     "--filename-opts posix\n", args->name);
  121                 *chars_allowed = 0;
  122                 return -errno;
  123             }
  124         } else {
  125             (void)close(fd);
  126             (void)unlink(filename);
  127             allowed[j] = i;
  128             j++;
  129         }
  130     }
  131     *chars_allowed = j;
  132 
  133     return 0;
  134 }
  135 
  136 /*
  137  *  stress_filename_ext()
  138  *  determine allowed for ext* filesystems
  139  */
  140 static void stress_filename_ext(size_t *chars_allowed)
  141 {
  142     size_t i, j;
  143 
  144     for (j = 0, i = 0; i < 256; i++) {
  145         if ((i == 0) || (i == '/'))
  146             continue;
  147         allowed[j] = i;
  148         j++;
  149     }
  150     *chars_allowed = j;
  151 }
  152 
  153 /*
  154  *  stress_filename_generate()
  155  *  generate a filename of length sz_max
  156  */
  157 static void stress_filename_generate(
  158     char *filename,
  159     const size_t sz_max,
  160     const char ch)
  161 {
  162     size_t i;
  163 
  164     for (i = 0; i < sz_max; i++) {
  165         filename[i] = ch;
  166     }
  167     if (*filename == '.')
  168         *filename = '_';
  169 
  170     filename[i] = '\0';
  171 }
  172 
  173 /*
  174  *  stress_filename_tidy()
  175  *  clean up residual files
  176  */
  177 static void stress_filename_tidy(const char *path)
  178 {
  179     DIR *dir;
  180 
  181     dir = opendir(path);
  182     if (dir) {
  183         struct dirent *d;
  184 
  185         while ((d = readdir(dir)) != NULL) {
  186             char filename[PATH_MAX];
  187 
  188             if (stress_is_dot_filename(d->d_name))
  189                 continue;
  190             (void)snprintf(filename, sizeof(filename),
  191                 "%s/%s", path, d->d_name);
  192             (void)unlink(filename);
  193         }
  194         (void)closedir(dir);
  195     }
  196     (void)rmdir(path);
  197 }
  198 
  199 /*
  200  *  stress_filename_generate_random()
  201  *  generate a filename of length sz_max with
  202  *  random selection from possible char set
  203  */
  204 static void stress_filename_generate_random(
  205     char *filename,
  206     const size_t sz_max,
  207     const size_t chars_allowed)
  208 {
  209     size_t i;
  210 
  211     for (i = 0; i < sz_max; i++) {
  212         const int j = mwc32() % chars_allowed;
  213         filename[i] = allowed[j];
  214     }
  215     if (*filename == '.')
  216         *filename = '_';
  217     filename[i] = '\0';
  218 }
  219 
  220 /*
  221  *  stress_filename_test()
  222  *  create a file, and check if it fails.
  223  *  should_pass = true - create must pass
  224  *  should_pass = false - expect it to fail (name too long)
  225  */
  226 static void stress_filename_test(
  227     const args_t *args,
  228     const char *filename,
  229     const size_t sz_max,
  230     const bool should_pass)
  231 {
  232     int fd;
  233 
  234     if ((fd = creat(filename, S_IRUSR | S_IWUSR)) < 0) {
  235         if ((!should_pass) && (errno == ENAMETOOLONG))
  236             return;
  237 
  238         pr_fail("%s: open failed on file of length "
  239             "%zu bytes, errno=%d (%s)\n",
  240             args->name, sz_max, errno, strerror(errno));
  241     } else {
  242         (void)close(fd);
  243         (void)unlink(filename);
  244     }
  245 }
  246 
  247 /*
  248  *  stress_filename()
  249  *  stress filename sizes etc
  250  */
  251 static int stress_filename(const args_t *args)
  252 {
  253     int ret, rc = EXIT_FAILURE;
  254     size_t sz_left, sz_max;
  255     char dirname[PATH_MAX - 256];
  256     char filename[PATH_MAX];
  257     char *ptr;
  258 #if defined(HAVE_SYS_STATVFS_H)
  259     struct statvfs buf;
  260 #endif
  261     pid_t pid;
  262     size_t i, chars_allowed = 0, sz;
  263 #if defined(__APPLE__)
  264     uint8_t filename_opt = STRESS_FILENAME_POSIX;
  265 #else
  266     uint8_t filename_opt = STRESS_FILENAME_PROBE;
  267 #endif
  268 
  269     (void)get_setting("filename-opts", &filename_opt);
  270 
  271     stress_temp_dir_args(args, dirname, sizeof(dirname));
  272     if (mkdir(dirname, S_IRWXU) < 0) {
  273         if (errno != EEXIST) {
  274             pr_fail_err("mkdir");
  275             return EXIT_FAILURE;
  276         }
  277     }
  278 
  279 #if defined(HAVE_SYS_STATVFS_H)
  280     if (statvfs(dirname, &buf) < 0) {
  281         pr_fail_err("statvfs");
  282         goto tidy_dir;
  283     }
  284 
  285     if (args->instance == 0)
  286         pr_dbg("%s: maximum file size: %lu bytes\n",
  287             args->name, (long unsigned) buf.f_namemax);
  288 #endif
  289 
  290     (void)shim_strlcpy(filename, dirname, sizeof(filename) - 1);
  291     ptr = filename + strlen(dirname);
  292     *(ptr++) = '/';
  293     *(ptr) = '\0';
  294     sz_left = sizeof(filename) - (ptr - filename);
  295 
  296 #if defined(HAVE_SYS_STATVFS_H)
  297     sz_max = (size_t)buf.f_namemax;
  298 #else
  299     sz_max = 256;
  300 #endif
  301 
  302     /* Some BSD systems return zero for sz_max */
  303     if (sz_max == 0)
  304         sz_max = 128;
  305     if (sz_max > PATH_MAX)
  306         sz_max = PATH_MAX;
  307 
  308     if (sz_left >= PATH_MAX) {
  309         pr_fail("%s: max file name larger than PATH_MAX\n", args->name);
  310         goto tidy_dir;
  311     }
  312 
  313     switch (filename_opt) {
  314     case STRESS_FILENAME_POSIX:
  315         (void)shim_strlcpy(allowed, posix_allowed, sizeof(allowed));
  316         chars_allowed = strlen(allowed);
  317         break;
  318     case STRESS_FILENAME_EXT:
  319         stress_filename_ext(&chars_allowed);
  320         break;
  321     case STRESS_FILENAME_PROBE:
  322     default:
  323         ret = stress_filename_probe(args, filename, ptr, &chars_allowed);
  324         if (ret < 0) {
  325             rc = exit_status(-ret);
  326             goto tidy_dir;
  327         }
  328         break;
  329     }
  330 
  331     if (args->instance == 0)
  332         pr_dbg("%s: filesystem allows %zu unique "
  333             "characters in a filename\n",
  334             args->name, chars_allowed);
  335 
  336     if (chars_allowed == 0) {
  337         pr_fail("%s: cannot determine allowed characters "
  338             "in a filename\n", args->name);
  339         goto tidy_dir;
  340     }
  341 
  342 again:
  343     if (!g_keep_stressing_flag) {
  344         /* Time to die */
  345         rc = EXIT_SUCCESS;
  346         goto tidy_dir;
  347     }
  348     pid = fork();
  349     if (pid < 0) {
  350         if ((errno == EAGAIN) || (errno == ENOMEM))
  351             goto again;
  352         pr_err("%s: fork failed: errno=%d: (%s)\n",
  353             args->name, errno, strerror(errno));
  354     } else if (pid > 0) {
  355         int status;
  356 
  357         (void)setpgid(pid, g_pgrp);
  358         /* Parent, wait for child */
  359         ret = waitpid(pid, &status, 0);
  360         if (ret < 0) {
  361             if (errno != EINTR)
  362                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  363                     args->name, errno, strerror(errno));
  364             (void)kill(pid, SIGTERM);
  365             (void)kill(pid, SIGKILL);
  366             (void)waitpid(pid, &status, 0);
  367         } else if (WIFSIGNALED(status)) {
  368             pr_dbg("%s: child died: %s (instance %d)\n",
  369                 args->name, stress_strsignal(WTERMSIG(status)),
  370                 args->instance);
  371             /* If we got killed by OOM killer, re-start */
  372             if (WTERMSIG(status) == SIGKILL) {
  373                 if (g_opt_flags & OPT_FLAGS_OOMABLE) {
  374                     log_system_mem_info();
  375                     pr_dbg("%s: assuming killed by OOM "
  376                         "killer, bailing out "
  377                         "(instance %d)\n",
  378                         args->name, args->instance);
  379                     _exit(0);
  380                 } else {
  381                     log_system_mem_info();
  382                     pr_dbg("%s: assuming killed by OOM "
  383                         "killer, restarting again "
  384                         "(instance %d)\n",
  385                         args->name, args->instance);
  386                     goto again;
  387                 }
  388             }
  389         }
  390     } else if (pid == 0) {
  391         /* Child, wrapped to catch OOMs */
  392 
  393         (void)setpgid(0, g_pgrp);
  394         stress_parent_died_alarm();
  395 
  396         /* Make sure this is killable by OOM killer */
  397         set_oom_adjustment(args->name, true);
  398 
  399         i = 0;
  400         sz = 1;
  401         do {
  402             const char ch = allowed[i];
  403             const size_t rnd_sz = 1 + (mwc32() % sz_max);
  404 
  405             i++;
  406             if (i >= chars_allowed)
  407                 i = 0;
  408 
  409             /* Should succeed */
  410             stress_filename_generate(ptr, 1, ch);
  411             stress_filename_test(args, filename, 1, true);
  412             stress_filename_generate_random(ptr, 1, chars_allowed);
  413             stress_filename_test(args, filename, 1, true);
  414 
  415             /* Should succeed */
  416             stress_filename_generate(ptr, sz_max, ch);
  417             stress_filename_test(args, filename, sz_max, true);
  418             stress_filename_generate_random(ptr, sz_max, chars_allowed);
  419             stress_filename_test(args, filename, sz_max, true);
  420 
  421             /* Should succeed */
  422             stress_filename_generate(ptr, sz_max - 1, ch);
  423             stress_filename_test(args, filename, sz_max - 1, true);
  424             stress_filename_generate_random(ptr, sz_max - 1, chars_allowed);
  425             stress_filename_test(args, filename, sz_max - 1, true);
  426 
  427             /* Should fail */
  428             stress_filename_generate(ptr, sz_max + 1, ch);
  429             stress_filename_test(args, filename, sz_max + 1, false);
  430             stress_filename_generate_random(ptr, sz_max + 1, chars_allowed);
  431             stress_filename_test(args, filename, sz_max + 1, false);
  432 
  433             /* Should succeed */
  434             stress_filename_generate(ptr, sz, ch);
  435             stress_filename_test(args, filename, sz, true);
  436             stress_filename_generate_random(ptr, sz, chars_allowed);
  437             stress_filename_test(args, filename, sz, true);
  438 
  439             /* Should succeed */
  440             stress_filename_generate(ptr, rnd_sz, ch);
  441             stress_filename_test(args, filename, rnd_sz, true);
  442             stress_filename_generate_random(ptr, rnd_sz, chars_allowed);
  443             stress_filename_test(args, filename, rnd_sz, true);
  444 
  445             sz++;
  446             if (sz > sz_max)
  447                 sz = 1;
  448             inc_counter(args);
  449         } while (keep_stressing());
  450         _exit(EXIT_SUCCESS);
  451     }
  452     rc = EXIT_SUCCESS;
  453 
  454 tidy_dir:
  455     (void)stress_filename_tidy(dirname);
  456 
  457     return rc;
  458 }
  459 
  460 stressor_info_t stress_filename_info = {
  461     .stressor = stress_filename,
  462     .class = CLASS_FILESYSTEM | CLASS_OS
  463 };