(root)/
util-linux-2.39/
sys-utils/
choom.c
       1  /*
       2   * choom - Change OOM score setting
       3   *
       4   * Copyright (C) 2018 Karel Zak <kzak@redhat.com>
       5   *
       6   * This program is free software; you can redistribute it and/or modify
       7   * it under the terms of the GNU General Public License as published by
       8   * the Free Software Foundation; either version 2 of the License, or
       9   * (at your option) any later version.
      10   *
      11   * This program is distributed in the hope that it would be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14   * GNU General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU General Public License along
      17   * with this program; if not, write to the Free Software Foundation, Inc.,
      18   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19   */
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <string.h>
      23  #include <unistd.h>
      24  #include <getopt.h>
      25  #include <errno.h>
      26  
      27  #include "nls.h"
      28  #include "c.h"
      29  #include "path.h"
      30  #include "strutils.h"
      31  #include "closestream.h"
      32  
      33  static void __attribute__((__noreturn__)) usage(void)
      34  {
      35  	FILE *out = stdout;
      36  	fputs(USAGE_HEADER, out);
      37  	fprintf(out,
      38  	      _(" %1$s [options] -p pid\n"
      39  		" %1$s [options] -n number -p pid\n"
      40  		" %1$s [options] -n number [--] command [args...]]\n"),
      41  		program_invocation_short_name);
      42  
      43  	fputs(USAGE_SEPARATOR, out);
      44  	fputs(_("Display and adjust OOM-killer score.\n"), out);
      45  
      46  	fputs(USAGE_OPTIONS, out);
      47  	fputs(_(" -n, --adjust <num>     specify the adjust score value\n"), out);
      48  	fputs(_(" -p, --pid <num>        process ID\n"), out);
      49  	fputs(USAGE_SEPARATOR, out);
      50  	printf(USAGE_HELP_OPTIONS(24));
      51  	printf(USAGE_MAN_TAIL("choom(1)"));
      52  	exit(EXIT_SUCCESS);
      53  }
      54  
      55  static int get_score(struct path_cxt *pc)
      56  {
      57  	int ret;
      58  
      59  	if (ul_path_read_s32(pc, &ret, "oom_score") != 0)
      60  		err(EXIT_FAILURE, _("failed to read OOM score value"));
      61  
      62  	return ret;
      63  }
      64  
      65  static int get_score_adj(struct path_cxt *pc)
      66  {
      67  	int ret;
      68  
      69  	if (ul_path_read_s32(pc, &ret, "oom_score_adj") != 0)
      70  		err(EXIT_FAILURE, _("failed to read OOM score adjust value"));
      71  
      72  	return ret;
      73  }
      74  
      75  static int set_score_adj(struct path_cxt *pc, int adj)
      76  {
      77  	return ul_path_write_s64(pc, adj, "oom_score_adj");
      78  }
      79  
      80  int main(int argc, char **argv)
      81  {
      82  	pid_t pid = 0;
      83  	int c, adj = 0, has_adj = 0;
      84  	struct path_cxt *pc = NULL;
      85  
      86  	static const struct option longopts[] = {
      87  		{ "adjust",  required_argument, NULL, 'n' },
      88  		{ "pid",     required_argument, NULL, 'p' },
      89  		{ "help",    no_argument,       NULL, 'h' },
      90  		{ "version", no_argument,       NULL, 'V' },
      91  		{ NULL,      0,                 NULL,  0  }
      92  	};
      93  
      94  	setlocale(LC_ALL, "");
      95  	bindtextdomain(PACKAGE, LOCALEDIR);
      96  	textdomain(PACKAGE);
      97  	close_stdout_atexit();
      98  
      99  	while ((c = getopt_long(argc, argv, "hn:p:V", longopts, NULL)) != -1) {
     100  		switch (c) {
     101  		case 'p':
     102  			pid = strtos32_or_err(optarg, _("invalid PID argument"));
     103  			break;
     104  		case 'n':
     105  			adj = strtos32_or_err(optarg, _("invalid adjust argument"));
     106  			has_adj = 1;
     107  			break;
     108  
     109  		case 'V':
     110  			print_version(EXIT_SUCCESS);
     111  		case 'h':
     112  			usage();
     113  		default:
     114  			errtryhelp(EXIT_FAILURE);
     115  		}
     116  	}
     117  
     118  	if (optind < argc && pid) {
     119  		warnx(_("invalid argument: %s"), argv[optind]);
     120  		errtryhelp(EXIT_FAILURE);
     121  	}
     122  	if (!pid && argc - optind < 1) {
     123  		warnx(_("no PID or COMMAND specified"));
     124  		errtryhelp(EXIT_FAILURE);
     125  	}
     126  	if (optind < argc && !has_adj) {
     127  		warnx(_("no OOM score adjust value specified"));
     128  		errtryhelp(EXIT_FAILURE);
     129  	}
     130  
     131  	pc = ul_new_path("/proc/%d", (int) (pid ? pid : getpid()));
     132  
     133  	/* Show */
     134  	if (!has_adj) {
     135  		printf(_("pid %d's current OOM score: %d\n"), pid, get_score(pc));
     136  		printf(_("pid %d's current OOM score adjust value: %d\n"), pid, get_score_adj(pc));
     137  
     138  	/* Change */
     139  	} else if (pid) {
     140  		int old = get_score_adj(pc);
     141  
     142  		if (set_score_adj(pc, adj))
     143  			err(EXIT_FAILURE, _("failed to set score adjust value"));
     144  
     145  		printf(_("pid %d's OOM score adjust value changed from %d to %d\n"), pid, old, adj);
     146  
     147  	/* Start new process */
     148  	} else {
     149  		if (set_score_adj(pc, adj))
     150  			err(EXIT_FAILURE, _("failed to set score adjust value"));
     151  		ul_unref_path(pc);
     152  		argv += optind;
     153  		execvp(argv[0], argv);
     154  		errexec(argv[0]);
     155  	}
     156  
     157  	ul_unref_path(pc);
     158  	return EXIT_SUCCESS;
     159  }