(root)/
util-linux-2.39/
sys-utils/
ipcrm.c
       1  /*
       2   * krishna balasubramanian 1993
       3   *
       4   * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
       5   * - added Native Language Support
       6   *
       7   * 1999-04-02 frank zago
       8   * - can now remove several id's in the same call
       9   *
      10   */
      11  
      12  #include <errno.h>
      13  #include <getopt.h>
      14  #include <stdio.h>
      15  #include <stdlib.h>
      16  #include <string.h>
      17  #include <sys/ipc.h>
      18  #include <sys/msg.h>
      19  #include <sys/sem.h>
      20  #include <sys/shm.h>
      21  #include <sys/types.h>
      22  #include "c.h"
      23  #include "nls.h"
      24  #include "strutils.h"
      25  #include "closestream.h"
      26  
      27  #ifndef HAVE_UNION_SEMUN
      28  /* according to X/OPEN we have to define it ourselves */
      29  union semun {
      30  	int val;
      31  	struct semid_ds *buf;
      32  	unsigned short int *array;
      33  	struct seminfo *__buf;
      34  };
      35  #endif
      36  
      37  typedef enum type_id {
      38  	SHM,
      39  	SEM,
      40  	MSG,
      41  	ALL
      42  } type_id;
      43  
      44  static int verbose = 0;
      45  
      46  /* print the usage */
      47  static void __attribute__((__noreturn__)) usage(void)
      48  {
      49  	FILE *out = stdout;
      50  	fputs(USAGE_HEADER, out);
      51  	fprintf(out, _(" %1$s [options]\n"
      52  		       " %1$s shm|msg|sem <id>...\n"), program_invocation_short_name);
      53  
      54  	fputs(USAGE_SEPARATOR, out);
      55  	fputs(_("Remove certain IPC resources.\n"), out);
      56  
      57  	fputs(USAGE_OPTIONS, out);
      58  	fputs(_(" -m, --shmem-id <id>        remove shared memory segment by id\n"), out);
      59  	fputs(_(" -M, --shmem-key <key>      remove shared memory segment by key\n"), out);
      60  	fputs(_(" -q, --queue-id <id>        remove message queue by id\n"), out);
      61  	fputs(_(" -Q, --queue-key <key>      remove message queue by key\n"), out);
      62  	fputs(_(" -s, --semaphore-id <id>    remove semaphore by id\n"), out);
      63  	fputs(_(" -S, --semaphore-key <key>  remove semaphore by key\n"), out);
      64  	fputs(_(" -a, --all[=shm|msg|sem]    remove all (in the specified category)\n"), out);
      65  	fputs(_(" -v, --verbose              explain what is being done\n"), out);
      66  
      67  	fputs(USAGE_SEPARATOR, out);
      68  	printf(USAGE_HELP_OPTIONS(28));
      69  	printf(USAGE_MAN_TAIL("ipcrm(1)"));
      70  
      71  	exit(EXIT_SUCCESS);
      72  }
      73  
      74  static int remove_id(int type, int iskey, int id)
      75  {
      76          int ret;
      77  	char *errmsg;
      78  	/* needed to delete semaphores */
      79  	union semun arg;
      80  	arg.val = 0;
      81  
      82  	/* do the removal */
      83  	switch (type) {
      84  	case SHM:
      85  		if (verbose)
      86  			printf(_("removing shared memory segment id `%d'\n"), id);
      87  		ret = shmctl(id, IPC_RMID, NULL);
      88  		break;
      89  	case MSG:
      90  		if (verbose)
      91  			printf(_("removing message queue id `%d'\n"), id);
      92  		ret = msgctl(id, IPC_RMID, NULL);
      93  		break;
      94  	case SEM:
      95  		if (verbose)
      96  			printf(_("removing semaphore id `%d'\n"), id);
      97  		ret = semctl(id, 0, IPC_RMID, arg);
      98  		break;
      99  	default:
     100  		errx(EXIT_FAILURE, "impossible occurred");
     101  	}
     102  
     103  	/* how did the removal go? */
     104  	if (ret < 0) {
     105  		switch (errno) {
     106  		case EACCES:
     107  		case EPERM:
     108  			errmsg = iskey ? _("permission denied for key") : _("permission denied for id");
     109  			break;
     110  		case EINVAL:
     111  			errmsg = iskey ? _("invalid key") : _("invalid id");
     112  			break;
     113  		case EIDRM:
     114  			errmsg = iskey ? _("already removed key") : _("already removed id");
     115  			break;
     116  		default:
     117  			err(EXIT_FAILURE, "%s", iskey ? _("key failed") : _("id failed"));
     118  		}
     119  		warnx("%s (%d)", errmsg, id);
     120  		return 1;
     121  	}
     122  	return 0;
     123  }
     124  
     125  static int remove_arg_list(type_id type, int argc, char **argv)
     126  {
     127  	int id;
     128  	char *end = NULL;
     129  	int nb_errors = 0;
     130  
     131  	do {
     132  		errno = 0;
     133  		id = strtoul(argv[0], &end, 10);
     134  		if (errno || !end || *end != 0) {
     135  			warnx(_("invalid id: %s"), argv[0]);
     136  			nb_errors++;
     137  		} else {
     138  			if (remove_id(type, 0, id))
     139  				nb_errors++;
     140  		}
     141  		argc--;
     142  		argv++;
     143  	} while (argc);
     144  	return (nb_errors);
     145  }
     146  
     147  static int deprecated_main(int argc, char **argv)
     148  {
     149  	type_id type;
     150  
     151  	if (!strcmp(argv[1], "shm"))
     152  		type = SHM;
     153  	else if (!strcmp(argv[1], "msg"))
     154  		type = MSG;
     155  	else if (!strcmp(argv[1], "sem"))
     156  		type = SEM;
     157  	else
     158  		return 0;
     159  
     160  	if (argc < 3) {
     161  		warnx(_("not enough arguments"));
     162  		errtryhelp(EXIT_FAILURE);
     163  	}
     164  
     165  	if (remove_arg_list(type, argc - 2, &argv[2]))
     166  		exit(EXIT_FAILURE);
     167  
     168  	printf(_("resource(s) deleted\n"));
     169  	return 1;
     170  }
     171  
     172  static unsigned long strtokey(const char *str, const char *errmesg)
     173  {
     174  	unsigned long num;
     175  	char *end = NULL;
     176  
     177  	if (str == NULL || *str == '\0')
     178  		goto err;
     179  	errno = 0;
     180  	/* keys are in hex or decimal */
     181  	num = strtoul(str, &end, 0);
     182  
     183  	if (errno || str == end || (end && *end))
     184  		goto err;
     185  
     186  	return num;
     187   err:
     188  	if (errno)
     189  		err(EXIT_FAILURE, "%s: '%s'", errmesg, str);
     190  	else
     191  		errx(EXIT_FAILURE, "%s: '%s'", errmesg, str);
     192  	return 0;
     193  }
     194  
     195  static int key_to_id(type_id type, char *s)
     196  {
     197  	int id;
     198  	/* keys are in hex or decimal */
     199  	key_t key = strtokey(s, "failed to parse argument");
     200  	if (key == IPC_PRIVATE) {
     201  		warnx(_("illegal key (%s)"), s);
     202  		return -1;
     203  	}
     204  	switch (type) {
     205  	case SHM:
     206  		id = shmget(key, 0, 0);
     207  		break;
     208  	case MSG:
     209  		id = msgget(key, 0);
     210  		break;
     211  	case SEM:
     212  		id = semget(key, 0, 0);
     213  		break;
     214  	case ALL:
     215  		abort();
     216  	default:
     217  		errx(EXIT_FAILURE, "impossible occurred");
     218  	}
     219  	if (id < 0) {
     220  		char *errmsg;
     221  		switch (errno) {
     222  		case EACCES:
     223  			errmsg = _("permission denied for key");
     224  			break;
     225  		case EIDRM:
     226  			errmsg = _("already removed key");
     227  			break;
     228  		case ENOENT:
     229  			errmsg = _("invalid key");
     230  			break;
     231  		default:
     232  			err(EXIT_FAILURE, _("key failed"));
     233  		}
     234  		warnx("%s (%s)", errmsg, s);
     235  	}
     236  	return id;
     237  }
     238  
     239  static int remove_all(type_id type)
     240  {
     241  	int ret = 0;
     242  	int id, rm_me, maxid;
     243  
     244  	struct shmid_ds shmseg;
     245  
     246  	struct semid_ds semary;
     247  	struct seminfo seminfo;
     248  	union semun arg;
     249  
     250  	struct msqid_ds msgque;
     251  	struct msginfo msginfo;
     252  
     253  	if (type == SHM || type == ALL) {
     254  		maxid = shmctl(0, SHM_INFO, &shmseg);
     255  		if (maxid < 0)
     256  			errx(EXIT_FAILURE,
     257  			     _("kernel not configured for shared memory"));
     258  		for (id = 0; id <= maxid; id++) {
     259  			rm_me = shmctl(id, SHM_STAT, &shmseg);
     260  			if (rm_me < 0)
     261  				continue;
     262  			ret |= remove_id(SHM, 0, rm_me);
     263  		}
     264  	}
     265  	if (type == SEM || type == ALL) {
     266  		arg.array = (ushort *) (void *)&seminfo;
     267  		maxid = semctl(0, 0, SEM_INFO, arg);
     268  		if (maxid < 0)
     269  			errx(EXIT_FAILURE,
     270  			     _("kernel not configured for semaphores"));
     271  		for (id = 0; id <= maxid; id++) {
     272  			arg.buf = (struct semid_ds *)&semary;
     273  			rm_me = semctl(id, 0, SEM_STAT, arg);
     274  			if (rm_me < 0)
     275  				continue;
     276  			ret |= remove_id(SEM, 0, rm_me);
     277  		}
     278  	}
     279  /* kFreeBSD hackery -- ah 20140723 */
     280  #ifndef MSG_STAT
     281  #define MSG_STAT 11
     282  #endif
     283  #ifndef MSG_INFO
     284  #define MSG_INFO 12
     285  #endif
     286  	if (type == MSG || type == ALL) {
     287  		maxid =
     288  		    msgctl(0, MSG_INFO, (struct msqid_ds *)(void *)&msginfo);
     289  		if (maxid < 0)
     290  			errx(EXIT_FAILURE,
     291  			     _("kernel not configured for message queues"));
     292  		for (id = 0; id <= maxid; id++) {
     293  			rm_me = msgctl(id, MSG_STAT, &msgque);
     294  			if (rm_me < 0)
     295  				continue;
     296  			ret |= remove_id(MSG, 0, rm_me);
     297  		}
     298  	}
     299  	return ret;
     300  }
     301  
     302  int main(int argc, char **argv)
     303  {
     304  	int c;
     305  	int ret = 0;
     306  	int id = -1;
     307  	int iskey;
     308  	int rm_all = 0;
     309  	type_id what_all = ALL;
     310  
     311  	static const struct option longopts[] = {
     312  		{"shmem-id", required_argument, NULL, 'm'},
     313  		{"shmem-key", required_argument, NULL, 'M'},
     314  		{"queue-id", required_argument, NULL, 'q'},
     315  		{"queue-key", required_argument, NULL, 'Q'},
     316  		{"semaphore-id", required_argument, NULL, 's'},
     317  		{"semaphore-key", required_argument, NULL, 'S'},
     318  		{"all", optional_argument, NULL, 'a'},
     319  		{"verbose", no_argument, NULL, 'v'},
     320  		{"version", no_argument, NULL, 'V'},
     321  		{"help", no_argument, NULL, 'h'},
     322  		{NULL, 0, NULL, 0}
     323  	};
     324  
     325  	/* if the command is executed without parameters, do nothing */
     326  	if (argc == 1)
     327  		return 0;
     328  
     329  	setlocale(LC_ALL, "");
     330  	bindtextdomain(PACKAGE, LOCALEDIR);
     331  	textdomain(PACKAGE);
     332  	close_stdout_atexit();
     333  
     334  	/* check to see if the command is being invoked in the old way if so
     335  	 * then remove argument list */
     336  	if (deprecated_main(argc, argv))
     337  		return EXIT_SUCCESS;
     338  
     339  	/* process new syntax to conform with SYSV ipcrm */
     340  	while((c = getopt_long(argc, argv, "q:m:s:Q:M:S:a::vhV", longopts, NULL)) != -1) {
     341  		iskey = 0;
     342  		switch (c) {
     343  		case 'M':
     344  			iskey = 1;
     345  			id = key_to_id(SHM, optarg);
     346  			if (id < 0) {
     347  				ret++;
     348  				break;
     349  			}
     350  			/* fallthrough */
     351  		case 'm':
     352  			if (!iskey)
     353  				id = strtos32_or_err(optarg, _("failed to parse argument"));
     354  			if (remove_id(SHM, iskey, id))
     355  				ret++;
     356  			break;
     357  		case 'Q':
     358  			iskey = 1;
     359  			id = key_to_id(MSG, optarg);
     360  			if (id < 0) {
     361  				ret++;
     362  				break;
     363  			}
     364  			/* fallthrough */
     365  		case 'q':
     366  			if (!iskey)
     367  				id = strtos32_or_err(optarg, _("failed to parse argument"));
     368  			if (remove_id(MSG, iskey, id))
     369  				ret++;
     370  			break;
     371  		case 'S':
     372  			iskey = 1;
     373  			id = key_to_id(SEM, optarg);
     374  			if (id < 0) {
     375  				ret++;
     376  				break;
     377  			}
     378  			/* fallthrough */
     379  		case 's':
     380  			if (!iskey)
     381  				id = strtos32_or_err(optarg, _("failed to parse argument"));
     382  			if (remove_id(SEM, iskey, id))
     383  				ret++;
     384  			break;
     385  		case 'a':
     386  			rm_all = 1;
     387  			if (optarg) {
     388  				if (!strcmp(optarg, "shm"))
     389  					what_all = SHM;
     390  				else if (!strcmp(optarg, "msg"))
     391  					what_all = MSG;
     392  				else if (!strcmp(optarg, "sem"))
     393  					what_all = SEM;
     394  				else
     395  					errx(EXIT_FAILURE,
     396  					     _("unknown argument: %s"), optarg);
     397  			} else {
     398  				what_all = ALL;
     399  			}
     400  			break;
     401  		case 'v':
     402  			verbose = 1;
     403  			break;
     404  
     405  		case 'h':
     406  			usage();
     407  		case 'V':
     408  			print_version(EXIT_SUCCESS);
     409  		default:
     410  			errtryhelp(EXIT_FAILURE);
     411  		}
     412  	}
     413  
     414  	if (rm_all && remove_all(what_all))
     415  		ret++;
     416  
     417  	/* print usage if we still have some arguments left over */
     418  	if (optind < argc) {
     419  		warnx(_("unknown argument: %s"), argv[optind]);
     420  		errtryhelp(EXIT_FAILURE);
     421  	}
     422  
     423  	return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
     424  }