"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-exec.c" (15 Mar 2019, 5354 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-exec.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 /*
   28  *  stress_set_exec_max()
   29  *  set maximum number of forks allowed
   30  */
   31 int stress_set_exec_max(const char *opt)
   32 {
   33     uint64_t exec_max;
   34 
   35     exec_max = get_uint64(opt);
   36     check_range("exec-max", exec_max,
   37         MIN_EXECS, MAX_EXECS);
   38     return set_setting("exec-max", TYPE_ID_INT64, &exec_max);
   39 }
   40 
   41 #if defined(__linux__)
   42 
   43 /*
   44  *  stress_exec_supported()
   45  *      check that we don't run this as root
   46  */
   47 static int stress_exec_supported(void)
   48 {
   49     /*
   50      *  Don't want to run this when running as root as
   51      *  this could allow somebody to try and run another
   52      *  executable as root.
   53      */
   54         if (geteuid() == 0) {
   55         pr_inf("exec stressor must not run as root, skipping the stressor\n");
   56                 return -1;
   57         }
   58         return 0;
   59 }
   60 
   61 /*
   62  *  stress_exec()
   63  *  stress by forking and exec'ing
   64  */
   65 static int stress_exec(const args_t *args)
   66 {
   67     pid_t pids[MAX_FORKS];
   68     char path[PATH_MAX + 1];
   69     ssize_t len;
   70 #if defined(HAVE_EXECVEAT)
   71     int fdexec;
   72 #endif
   73     uint64_t exec_fails = 0, exec_calls = 0;
   74     uint64_t exec_max = DEFAULT_EXECS;
   75     char *argv_new[] = { NULL, "--exec-exit", NULL };
   76     char *env_new[] = { NULL };
   77 
   78     (void)get_setting("exec-max", &exec_max);
   79 
   80     /*
   81      *  Determine our own self as the executable, e.g. run stress-ng
   82      */
   83     len = readlink("/proc/self/exe", path, sizeof(path));
   84     if (len < 0 || len > PATH_MAX) {
   85         pr_fail("%s: readlink on /proc/self/exe failed, errno=%d (%s)\n",
   86             args->name, errno, strerror(errno));
   87         return EXIT_FAILURE;
   88     }
   89     path[len] = '\0';
   90     argv_new[0] = path;
   91 
   92 #if defined(HAVE_EXECVEAT)
   93     fdexec = open(path, O_PATH);
   94     if (fdexec < 0) {
   95         pr_fail("%s: open O_PATH on /proc/self/exe failed, errno=%d (%s)\n",
   96             args->name, errno, strerror(errno));
   97         return EXIT_FAILURE;
   98     }
   99 #endif
  100 
  101     do {
  102         unsigned int i;
  103 
  104         (void)memset(pids, 0, sizeof(pids));
  105 
  106         for (i = 0; i < exec_max; i++) {
  107             (void)mwc8();       /* force new random number */
  108 
  109             pids[i] = fork();
  110 
  111             if (pids[i] == 0) {
  112                 int ret, fd_out, fd_in, rc;
  113                 const int which = mwc8() % 3;
  114 
  115                 (void)setpgid(0, g_pgrp);
  116                 stress_parent_died_alarm();
  117 
  118                 if ((fd_out = open("/dev/null", O_WRONLY)) < 0) {
  119                     pr_fail("%s: child open on "
  120                         "/dev/null failed\n", args->name);
  121                     _exit(EXIT_FAILURE);
  122                 }
  123                 if ((fd_in = open("/dev/zero", O_RDONLY)) < 0) {
  124                     pr_fail("%s: child open on "
  125                         "/dev/zero failed\n", args->name);
  126                     (void)close(fd_out);
  127                     _exit(EXIT_FAILURE);
  128                 }
  129                 (void)dup2(fd_out, STDOUT_FILENO);
  130                 (void)dup2(fd_out, STDERR_FILENO);
  131                 (void)dup2(fd_in, STDIN_FILENO);
  132                 (void)close(fd_out);
  133                 (void)close(fd_in);
  134                 ret = stress_drop_capabilities(args->name);
  135                 (void)ret;
  136 
  137                 switch (which) {
  138                 case 0:
  139                     CASE_FALLTHROUGH;
  140                 default:
  141                     ret = execve(path, argv_new, env_new);
  142                     break;
  143 #if defined(HAVE_EXECVEAT)
  144                 case 1:
  145                     ret = shim_execveat(0, path, argv_new, env_new, AT_EMPTY_PATH);
  146                     break;
  147                 case 2:
  148                     ret = shim_execveat(fdexec, "", argv_new, env_new, AT_EMPTY_PATH);
  149                     break;
  150 #endif
  151                 }
  152 
  153                 rc = EXIT_SUCCESS;
  154                 if (ret < 0) {
  155                     switch (errno) {
  156                     case ENOMEM:
  157                         CASE_FALLTHROUGH;
  158                     case EMFILE:
  159                         rc = EXIT_NO_RESOURCE;
  160                         break;
  161                     case EAGAIN:
  162                         /* Ignore as an error */
  163                         rc = EXIT_SUCCESS;
  164                         break;
  165                     default:
  166                         rc = EXIT_FAILURE;
  167                         break;
  168                     }
  169                 }
  170 
  171                 /* Child, immediately exit */
  172                 _exit(rc);
  173             }
  174             if (pids[i] > -1)
  175                 (void)setpgid(pids[i], g_pgrp);
  176             if (!g_keep_stressing_flag)
  177                 break;
  178         }
  179         for (i = 0; i < exec_max; i++) {
  180             if (pids[i] > 0) {
  181                 int status;
  182                 /* Parent, wait for child */
  183                 (void)waitpid(pids[i], &status, 0);
  184                 exec_calls++;
  185                 inc_counter(args);
  186                 if (WEXITSTATUS(status) != EXIT_SUCCESS)
  187                     exec_fails++;
  188             }
  189         }
  190     } while (keep_stressing());
  191 
  192 #if defined(HAVE_EXECVEAT)
  193     (void)close(fdexec);
  194 #endif
  195 
  196     if ((exec_fails > 0) && (g_opt_flags & OPT_FLAGS_VERIFY)) {
  197         pr_fail("%s: %" PRIu64 " execs failed (%.2f%%)\n",
  198             args->name, exec_fails,
  199             (double)exec_fails * 100.0 / (double)(exec_calls));
  200     }
  201 
  202     return EXIT_SUCCESS;
  203 }
  204 
  205 stressor_info_t stress_exec_info = {
  206     .stressor = stress_exec,
  207     .supported = stress_exec_supported,
  208     .class = CLASS_SCHEDULER | CLASS_OS
  209 };
  210 #else
  211 stressor_info_t stress_exec_info = {
  212     .stressor = stress_not_implemented,
  213     .class = CLASS_SCHEDULER | CLASS_OS
  214 };
  215 #endif