1  /* Original author unknown, may be "krishna balasub@cis.ohio-state.edu" */
       2  /*
       3   * Modified Sat Oct  9 10:55:28 1993 for 0.99.13
       4   *
       5   * Patches from Mike Jagdis (jaggy@purplet.demon.co.uk) applied Wed Feb 8
       6   * 12:12:21 1995 by faith@cs.unc.edu to print numeric uids if no passwd file
       7   * entry.
       8   *
       9   * Patch from arnolds@ifns.de (Heinz-Ado Arnolds) applied Mon Jul 1 19:30:41
      10   * 1996 by janl@math.uio.no to add code missing in case PID: clauses.
      11   *
      12   * Patched to display the key field -- hy@picksys.com 12/18/96
      13   *
      14   * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL>
      15   * - added Native Language Support
      16   */
      17  
      18  #include <errno.h>
      19  #include <getopt.h>
      20  
      21  #include "c.h"
      22  #include "nls.h"
      23  #include "closestream.h"
      24  #include "timeutils.h"
      25  #include "strutils.h"
      26  
      27  #include "ipcutils.h"
      28  
      29  enum output_formats {
      30  	NOTSPECIFIED,
      31  	LIMITS,
      32  	STATUS,
      33  	CREATOR,
      34  	TIME,
      35  	PID
      36  };
      37  enum {
      38  	OPT_HUMAN = CHAR_MAX + 1
      39  };
      40  
      41  static void do_shm (char format, int unit);
      42  static void print_shm (int id, int unit);
      43  static void do_sem (char format);
      44  static void print_sem (int id);
      45  static void do_msg (char format, int unit);
      46  static void print_msg (int id, int unit);
      47  
      48  static inline char *ctime64(int64_t *t)
      49  {
      50  	static char buf[CTIME_BUFSIZ];
      51  
      52  	/* we read time as int64_t from /proc, so cast... */
      53  	ctime_r((time_t *)t, buf);
      54  	return buf;
      55  }
      56  
      57  static void __attribute__((__noreturn__)) usage(void)
      58  {
      59  	FILE *out = stdout;
      60  	fputs(USAGE_HEADER, out);
      61  	fprintf(out, _(" %1$s [resource-option...] [output-option]\n"
      62  		       " %1$s -m|-q|-s -i <id>\n"), program_invocation_short_name);
      63  
      64  	fputs(USAGE_SEPARATOR, out);
      65  	fputs(_("Show information on IPC facilities.\n"), out);
      66  
      67  	fputs(USAGE_OPTIONS, out);
      68  	fputs(_(" -i, --id <id>  print details on resource identified by <id>\n"), out);
      69  	printf(USAGE_HELP_OPTIONS(16));
      70  
      71  	fputs(USAGE_SEPARATOR, out);
      72  	fputs(_("Resource options:\n"), out);
      73  	fputs(_(" -m, --shmems      shared memory segments\n"), out);
      74  	fputs(_(" -q, --queues      message queues\n"), out);
      75  	fputs(_(" -s, --semaphores  semaphores\n"), out);
      76  	fputs(_(" -a, --all         all (default)\n"), out);
      77  
      78  	fputs(USAGE_SEPARATOR, out);
      79  	fputs(_("Output options:\n"), out);
      80  	fputs(_(" -t, --time        show attach, detach and change times\n"), out);
      81  	fputs(_(" -p, --pid         show PIDs of creator and last operator\n"), out);
      82  	fputs(_(" -c, --creator     show creator and owner\n"), out);
      83  	fputs(_(" -l, --limits      show resource limits\n"), out);
      84  	fputs(_(" -u, --summary     show status summary\n"), out);
      85  	fputs(_("     --human       show sizes in human-readable format\n"), out);
      86  	fputs(_(" -b, --bytes       show sizes in bytes\n"), out);
      87  	printf(USAGE_MAN_TAIL("ipcs(1)"));
      88  
      89  	exit(EXIT_SUCCESS);
      90  }
      91  
      92  int main (int argc, char **argv)
      93  {
      94  	int opt, msg = 0, shm = 0, sem = 0, id = 0, specific = 0;
      95  	char format = NOTSPECIFIED;
      96  	int unit = IPC_UNIT_DEFAULT;
      97  	static const struct option longopts[] = {
      98  		{"id", required_argument, NULL, 'i'},
      99  		{"queues", no_argument, NULL, 'q'},
     100  		{"shmems", no_argument, NULL, 'm'},
     101  		{"semaphores", no_argument, NULL, 's'},
     102  		{"all", no_argument, NULL, 'a'},
     103  		{"time", no_argument, NULL, 't'},
     104  		{"pid", no_argument, NULL, 'p'},
     105  		{"creator", no_argument, NULL, 'c'},
     106  		{"limits", no_argument, NULL, 'l'},
     107  		{"summary", no_argument, NULL, 'u'},
     108  		{"human", no_argument, NULL, OPT_HUMAN},
     109  		{"bytes", no_argument, NULL, 'b'},
     110  		{"version", no_argument, NULL, 'V'},
     111  		{"help", no_argument, NULL, 'h'},
     112  		{NULL, 0, NULL, 0}
     113  	};
     114  	char options[] = "i:qmsatpclubVh";
     115  
     116  	setlocale(LC_ALL, "");
     117  	bindtextdomain(PACKAGE, LOCALEDIR);
     118  	textdomain(PACKAGE);
     119  	close_stdout_atexit();
     120  
     121  	while ((opt = getopt_long(argc, argv, options, longopts, NULL)) != -1) {
     122  		switch (opt) {
     123  		case 'i':
     124  			id = strtos32_or_err(optarg, _("failed to parse id argument"));
     125  			specific = 1;
     126  			break;
     127  		case 'a':
     128  			msg = shm = sem = 1;
     129  			break;
     130  		case 'q':
     131  			msg = 1;
     132  			break;
     133  		case 'm':
     134  			shm = 1;
     135  			break;
     136  		case 's':
     137  			sem = 1;
     138  			break;
     139  		case 't':
     140  			format = TIME;
     141  			break;
     142  		case 'c':
     143  			format = CREATOR;
     144  			break;
     145  		case 'p':
     146  			format = PID;
     147  			break;
     148  		case 'l':
     149  			format = LIMITS;
     150  			break;
     151  		case 'u':
     152  			format = STATUS;
     153  			break;
     154  		case OPT_HUMAN:
     155  			unit = IPC_UNIT_HUMAN;
     156  			break;
     157  		case 'b':
     158  			unit = IPC_UNIT_BYTES;
     159  			break;
     160  
     161  		case 'h':
     162  			usage();
     163  		case 'V':
     164  			print_version(EXIT_SUCCESS);
     165  		default:
     166  			errtryhelp(EXIT_FAILURE);
     167  		}
     168  	}
     169  
     170  	if (specific && (msg + shm + sem != 1))
     171  		errx (EXIT_FAILURE,
     172  		      _("when using an ID, a single resource must be specified"));
     173  	if (specific) {
     174  		if (msg)
     175  			print_msg (id, unit);
     176  		if (shm)
     177  			print_shm (id, unit);
     178  		if (sem)
     179  			print_sem (id);
     180  	} else {
     181  		if (!msg && !shm && !sem)
     182  			msg = shm = sem = 1;
     183  		printf ("\n");
     184  		if (msg) {
     185  			do_msg (format, unit);
     186  			printf ("\n");
     187  		}
     188  		if (shm) {
     189  			do_shm (format, unit);
     190  			printf ("\n");
     191  		}
     192  		if (sem) {
     193  			do_sem (format);
     194  			printf ("\n");
     195  		}
     196  	}
     197  	return EXIT_SUCCESS;
     198  }
     199  
     200  static void do_shm (char format, int unit)
     201  {
     202  	struct passwd *pw;
     203  	struct shm_data *shmds, *shmdsp;
     204  
     205  	switch (format) {
     206  	case LIMITS:
     207  	{
     208  		struct ipc_limits lim;
     209  		uint64_t tmp, pgsz = getpagesize();
     210  
     211  		if (ipc_shm_get_limits(&lim)) {
     212  			printf (_("unable to fetch shared memory limits\n"));
     213  			return;
     214  		}
     215  		printf (_("------ Shared Memory Limits --------\n"));
     216  		printf (_("max number of segments = %ju\n"), lim.shmmni);
     217  		ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_KB : unit,
     218  			       _("max seg size"), lim.shmmax, "\n", 0);
     219  
     220  		if (unit == IPC_UNIT_KB || unit == IPC_UNIT_DEFAULT) {
     221  			tmp = (uint64_t) lim.shmall * (pgsz / 1024);
     222  			if (lim.shmall != 0 && tmp / lim.shmall != pgsz / 1024)
     223  				tmp = UINT64_MAX - (UINT64_MAX % (pgsz / 1024));
     224  
     225  			ipc_print_size(IPC_UNIT_DEFAULT, _("max total shared memory (kbytes)"), tmp, "\n", 0);
     226  		}
     227  		else {
     228  			tmp = (uint64_t) lim.shmall * pgsz;
     229  			/* overflow handling, at least we don't print ridiculous small values */
     230  			if (lim.shmall != 0 && tmp / lim.shmall != pgsz)
     231  			        tmp = UINT64_MAX - (UINT64_MAX % pgsz);
     232  
     233  			ipc_print_size(unit, _("max total shared memory"), tmp, "\n", 0);
     234  		}
     235  		ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_BYTES : unit,
     236  			       _("min seg size"), lim.shmmin, "\n", 0);
     237  		return;
     238  	}
     239  	case STATUS:
     240  	{
     241  		int maxid;
     242  		struct shmid_ds shmbuf;
     243  		struct shm_info *shm_info;
     244  
     245  		maxid = shmctl (0, SHM_INFO, &shmbuf);
     246  		shm_info =  (struct shm_info *) &shmbuf;
     247  		if (maxid < 0) {
     248  			printf (_("kernel not configured for shared memory\n"));
     249  			return;
     250  		}
     251  
     252  		printf (_("------ Shared Memory Status --------\n"));
     253  		/*
     254  		 * TRANSLATORS: This output format is maintained for backward
     255  		 * compatibility as ipcs is used in scripts. For consistency
     256  		 * with the rest, the translated form can follow this model:
     257  		 *
     258  		 * "segments allocated = %d\n"
     259  		 * "pages allocated = %ld\n"
     260  		 * "pages resident = %ld\n"
     261  		 * "pages swapped = %ld\n"
     262  		 * "swap performance = %ld attempts, %ld successes\n"
     263  		 */
     264  		printf (_("segments allocated %d\n"
     265  			  "pages allocated %ld\n"
     266  			  "pages resident  %ld\n"
     267  			  "pages swapped   %ld\n"
     268  			  "Swap performance: %ld attempts\t %ld successes\n"),
     269  			shm_info->used_ids,
     270  			shm_info->shm_tot,
     271  			shm_info->shm_rss,
     272  			shm_info->shm_swp,
     273  			shm_info->swap_attempts, shm_info->swap_successes);
     274  		return;
     275  	}
     276  
     277  	/*
     278  	 * Headers only
     279  	 */
     280  	case CREATOR:
     281  		printf (_("------ Shared Memory Segment Creators/Owners --------\n"));
     282  		printf ("%-10s %-10s %-10s %-10s %-10s %-10s\n",
     283  			_("shmid"),_("perms"),_("cuid"),_("cgid"),_("uid"),_("gid"));
     284  		break;
     285  
     286  	case TIME:
     287  		printf (_("------ Shared Memory Attach/Detach/Change Times --------\n"));
     288  		printf ("%-10s %-10s %-20s %-20s %-20s\n",
     289  			_("shmid"),_("owner"),_("attached"),_("detached"),
     290  			_("changed"));
     291  		break;
     292  
     293  	case PID:
     294  		printf (_("------ Shared Memory Creator/Last-op PIDs --------\n"));
     295  		printf ("%-10s %-10s %-10s %-10s\n",
     296  			_("shmid"),_("owner"),_("cpid"),_("lpid"));
     297  		break;
     298  
     299  	default:
     300  		printf (_("------ Shared Memory Segments --------\n"));
     301  		printf ("%-10s %-10s %-10s %-10s %-10s %-10s %-12s\n",
     302  			_("key"),_("shmid"),_("owner"),_("perms"),
     303  			unit == IPC_UNIT_HUMAN ? _("size") : _("bytes"),
     304  			_("nattch"),_("status"));
     305  		break;
     306  	}
     307  
     308  	/*
     309  	 * Print data
     310  	 */
     311  	if (ipc_shm_get_info(-1, &shmds) < 1)
     312  		return;
     313  
     314  	for (shmdsp = shmds; shmdsp->next != NULL; shmdsp = shmdsp->next) {
     315  		if (format == CREATOR)  {
     316  			ipc_print_perms(stdout, &shmdsp->shm_perm);
     317  			continue;
     318  		}
     319  		pw = getpwuid(shmdsp->shm_perm.uid);
     320  		switch (format) {
     321  		case TIME:
     322  			if (pw)
     323  				printf ("%-10d %-10.10s", shmdsp->shm_perm.id, pw->pw_name);
     324  			else
     325  				printf ("%-10d %-10u", shmdsp->shm_perm.id, shmdsp->shm_perm.uid);
     326  			/* ctime uses static buffer: use separate calls */
     327  			printf(" %-20.16s", shmdsp->shm_atim
     328  			       ? ctime64(&shmdsp->shm_atim) + 4 : _("Not set"));
     329  			printf(" %-20.16s", shmdsp->shm_dtim
     330  			       ? ctime64(&shmdsp->shm_dtim) + 4 : _("Not set"));
     331  			printf(" %-20.16s\n", shmdsp->shm_ctim
     332  			       ? ctime64(&shmdsp->shm_ctim) + 4 : _("Not set"));
     333  			break;
     334  		case PID:
     335  			if (pw)
     336  				printf ("%-10d %-10.10s", shmdsp->shm_perm.id, pw->pw_name);
     337  			else
     338  				printf ("%-10d %-10u", shmdsp->shm_perm.id, shmdsp->shm_perm.uid);
     339  			printf (" %-10u %-10u\n",
     340  				shmdsp->shm_cprid, shmdsp->shm_lprid);
     341  			break;
     342  
     343  		default:
     344  			printf("0x%08x ", shmdsp->shm_perm.key);
     345  			if (pw)
     346  				printf ("%-10d %-10.10s", shmdsp->shm_perm.id, pw->pw_name);
     347  			else
     348  				printf ("%-10d %-10u", shmdsp->shm_perm.id, shmdsp->shm_perm.uid);
     349  			printf (" %-10o ", shmdsp->shm_perm.mode & 0777);
     350  
     351  			if (unit == IPC_UNIT_HUMAN)
     352  				ipc_print_size(unit, NULL, shmdsp->shm_segsz, "    ", 6);
     353  			else
     354  				ipc_print_size(unit, NULL, shmdsp->shm_segsz, NULL, -10);
     355  
     356  			printf (" %-10ju %-6s %-6s\n",
     357  				shmdsp->shm_nattch,
     358  				shmdsp->shm_perm.mode & SHM_DEST ? _("dest") : " ",
     359  				shmdsp->shm_perm.mode & SHM_LOCKED ? _("locked") : " ");
     360  			break;
     361  		}
     362  	}
     363  
     364  	ipc_shm_free_info(shmds);
     365  }
     366  
     367  static void do_sem (char format)
     368  {
     369  	struct passwd *pw;
     370  	struct sem_data *semds, *semdsp;
     371  
     372  	switch (format) {
     373  	case LIMITS:
     374  	{
     375  		struct ipc_limits lim;
     376  
     377  		if (ipc_sem_get_limits(&lim)) {
     378  			printf (_("unable to fetch semaphore limits\n"));
     379  			return;
     380  		}
     381  		printf (_("------ Semaphore Limits --------\n"));
     382  		printf (_("max number of arrays = %d\n"), lim.semmni);
     383  		printf (_("max semaphores per array = %d\n"), lim.semmsl);
     384  		printf (_("max semaphores system wide = %d\n"), lim.semmns);
     385  		printf (_("max ops per semop call = %d\n"), lim.semopm);
     386  		printf (_("semaphore max value = %u\n"), lim.semvmx);
     387  		return;
     388  	}
     389  	case STATUS:
     390  	{
     391  		struct seminfo seminfo;
     392  		union semun arg;
     393  		arg.array = (ushort *)  (void *) &seminfo;
     394  		if (semctl (0, 0, SEM_INFO, arg) < 0) {
     395  			printf (_("kernel not configured for semaphores\n"));
     396  			return;
     397  		}
     398  		printf (_("------ Semaphore Status --------\n"));
     399  		printf (_("used arrays = %d\n"), seminfo.semusz);
     400  		printf (_("allocated semaphores = %d\n"), seminfo.semaem);
     401  		return;
     402  	}
     403  
     404  	case CREATOR:
     405  		printf (_("------ Semaphore Arrays Creators/Owners --------\n"));
     406  		printf ("%-10s %-10s %-10s %-10s %-10s %-10s\n",
     407  			_("semid"),_("perms"),_("cuid"),_("cgid"),_("uid"),_("gid"));
     408  		break;
     409  
     410  	case TIME:
     411  		printf (_("------ Semaphore Operation/Change Times --------\n"));
     412  		printf ("%-8s %-10s %-26.24s %-26.24s\n",
     413  			_("semid"),_("owner"),_("last-op"),_("last-changed"));
     414  		break;
     415  
     416  	case PID:
     417  		break;
     418  
     419  	default:
     420  		printf (_("------ Semaphore Arrays --------\n"));
     421  		printf ("%-10s %-10s %-10s %-10s %-10s\n",
     422  			_("key"),_("semid"),_("owner"),_("perms"),_("nsems"));
     423  		break;
     424  	}
     425  
     426  	/*
     427  	 * Print data
     428  	 */
     429  	if (ipc_sem_get_info(-1, &semds) < 1)
     430  		return;
     431  
     432  	for (semdsp = semds; semdsp->next != NULL; semdsp = semdsp->next) {
     433  		if (format == CREATOR)  {
     434  			ipc_print_perms(stdout, &semdsp->sem_perm);
     435  			continue;
     436  		}
     437  		pw = getpwuid(semdsp->sem_perm.uid);
     438  		switch (format) {
     439  		case TIME:
     440  			if (pw)
     441  				printf ("%-8d %-10.10s", semdsp->sem_perm.id, pw->pw_name);
     442  			else
     443  				printf ("%-8d %-10u", semdsp->sem_perm.id, semdsp->sem_perm.uid);
     444  			printf ("  %-26.24s", semdsp->sem_otime
     445  				? ctime64(&semdsp->sem_otime) : _("Not set"));
     446  			printf (" %-26.24s\n", semdsp->sem_ctime
     447  				? ctime64( &semdsp->sem_ctime) : _("Not set"));
     448  			break;
     449  		case PID:
     450  			break;
     451  
     452  		default:
     453  			printf("0x%08x ", semdsp->sem_perm.key);
     454  			if (pw)
     455  				printf ("%-10d %-10.10s", semdsp->sem_perm.id, pw->pw_name);
     456  			else
     457  				printf ("%-10d %-10u", semdsp->sem_perm.id, semdsp->sem_perm.uid);
     458  			printf (" %-10o %-10ju\n",
     459  				semdsp->sem_perm.mode & 0777,
     460  				semdsp->sem_nsems);
     461  			break;
     462  		}
     463  	}
     464  
     465  	ipc_sem_free_info(semds);
     466  }
     467  
     468  static void do_msg (char format, int unit)
     469  {
     470  	struct passwd *pw;
     471  	struct msg_data *msgds, *msgdsp;
     472  
     473  	switch (format) {
     474  	case LIMITS:
     475  	{
     476  		struct ipc_limits lim;
     477  
     478  		if (ipc_msg_get_limits(&lim)) {
     479  			printf (_("unable to fetch message limits\n"));
     480  			return;
     481  		}
     482  		printf (_("------ Messages Limits --------\n"));
     483  		printf (_("max queues system wide = %d\n"), lim.msgmni);
     484  		ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_BYTES : unit,
     485  			       _("max size of message"), lim.msgmax, "\n", 0);
     486  		ipc_print_size(unit == IPC_UNIT_DEFAULT ? IPC_UNIT_BYTES : unit,
     487  			       _("default max size of queue"), lim.msgmnb, "\n", 0);
     488  		return;
     489  	}
     490  	case STATUS:
     491  	{
     492  		struct msginfo msginfo;
     493  		if (msgctl (0, MSG_INFO, (struct msqid_ds *) (void *) &msginfo) < 0) {
     494  			printf (_("kernel not configured for message queues\n"));
     495  			return;
     496  		}
     497  		printf (_("------ Messages Status --------\n"));
     498  #ifndef __FreeBSD_kernel__
     499  		printf (_("allocated queues = %d\n"), msginfo.msgpool);
     500  		printf (_("used headers = %d\n"), msginfo.msgmap);
     501  #endif
     502  		ipc_print_size(unit, _("used space"), msginfo.msgtql,
     503  			       unit == IPC_UNIT_DEFAULT ? _(" bytes\n") : "\n", 0);
     504  		return;
     505  	}
     506  	case CREATOR:
     507  		printf (_("------ Message Queues Creators/Owners --------\n"));
     508  		printf ("%-10s %-10s %-10s %-10s %-10s %-10s\n",
     509  			_("msqid"),_("perms"),_("cuid"),_("cgid"),_("uid"),_("gid"));
     510  		break;
     511  
     512  	case TIME:
     513  		printf (_("------ Message Queues Send/Recv/Change Times --------\n"));
     514  		printf ("%-8s %-10s %-20s %-20s %-20s\n",
     515  			_("msqid"),_("owner"),_("send"),_("recv"),_("change"));
     516  		break;
     517  
     518  	case PID:
     519  		printf (_("------ Message Queues PIDs --------\n"));
     520  		printf ("%-10s %-10s %-10s %-10s\n",
     521  			_("msqid"),_("owner"),_("lspid"),_("lrpid"));
     522  		break;
     523  
     524  	default:
     525  		printf (_("------ Message Queues --------\n"));
     526  		printf ("%-10s %-10s %-10s %-10s %-12s %-12s\n",
     527  			_("key"), _("msqid"), _("owner"), _("perms"),
     528  			unit == IPC_UNIT_HUMAN ? _("size") : _("used-bytes"),
     529  			_("messages"));
     530  		break;
     531  	}
     532  
     533  	/*
     534  	 * Print data
     535  	 */
     536  	if (ipc_msg_get_info(-1, &msgds) < 1)
     537  		return;
     538  
     539  	for (msgdsp = msgds; msgdsp->next != NULL; msgdsp = msgdsp->next) {
     540  		if (format == CREATOR) {
     541  			ipc_print_perms(stdout, &msgdsp->msg_perm);
     542  			continue;
     543  		}
     544  		pw = getpwuid(msgdsp->msg_perm.uid);
     545  		switch (format) {
     546  		case TIME:
     547  			if (pw)
     548  				printf ("%-8d %-10.10s", msgdsp->msg_perm.id, pw->pw_name);
     549  			else
     550  				printf ("%-8d %-10u", msgdsp->msg_perm.id, msgdsp->msg_perm.uid);
     551  			printf (" %-20.16s", msgdsp->q_stime
     552  				? ctime64(&msgdsp->q_stime) + 4 : _("Not set"));
     553  			printf (" %-20.16s", msgdsp->q_rtime
     554  				? ctime64(&msgdsp->q_rtime) + 4 : _("Not set"));
     555  			printf (" %-20.16s\n", msgdsp->q_ctime
     556  				? ctime64(&msgdsp->q_ctime) + 4 : _("Not set"));
     557  			break;
     558  		case PID:
     559  			if (pw)
     560  				printf ("%-8d %-10.10s", msgdsp->msg_perm.id, pw->pw_name);
     561  			else
     562  				printf ("%-8d %-10u", msgdsp->msg_perm.id, msgdsp->msg_perm.uid);
     563  			printf ("  %5d     %5d\n",
     564  				msgdsp->q_lspid, msgdsp->q_lrpid);
     565  			break;
     566  
     567  		default:
     568  			printf( "0x%08x ",msgdsp->msg_perm.key );
     569  			if (pw)
     570  				printf ("%-10d %-10.10s", msgdsp->msg_perm.id, pw->pw_name);
     571  			else
     572  				printf ("%-10d %-10u", msgdsp->msg_perm.id, msgdsp->msg_perm.uid);
     573  			printf (" %-10o ", msgdsp->msg_perm.mode & 0777);
     574  
     575  			if (unit == IPC_UNIT_HUMAN)
     576  				ipc_print_size(unit, NULL, msgdsp->q_cbytes, "      ", 6);
     577  			else
     578  				ipc_print_size(unit, NULL, msgdsp->q_cbytes, NULL, -12);
     579  
     580  			printf (" %-12ju\n", msgdsp->q_qnum);
     581  			break;
     582  		}
     583  	}
     584  
     585  	ipc_msg_free_info(msgds);
     586  }
     587  
     588  static void print_shm(int shmid, int unit)
     589  {
     590  	struct shm_data *shmdata;
     591  
     592  	if (ipc_shm_get_info(shmid, &shmdata) < 1) {
     593  		warnx(_("id %d not found"), shmid);
     594  		return;
     595  	}
     596  
     597  	printf(_("\nShared memory Segment shmid=%d\n"), shmid);
     598  	printf(_("uid=%u\tgid=%u\tcuid=%u\tcgid=%u\n"),
     599  	       shmdata->shm_perm.uid, shmdata->shm_perm.gid,
     600  	       shmdata->shm_perm.cuid, shmdata->shm_perm.cgid);
     601  	printf(_("mode=%#o\taccess_perms=%#o\n"), shmdata->shm_perm.mode,
     602  	       shmdata->shm_perm.mode & 0777);
     603  	ipc_print_size(unit, unit == IPC_UNIT_HUMAN ? _("size=") : _("bytes="),
     604  		       shmdata->shm_segsz, "\t", 0);
     605  	printf(_("lpid=%u\tcpid=%u\tnattch=%jd\n"),
     606  	       shmdata->shm_lprid, shmdata->shm_cprid,
     607  	       shmdata->shm_nattch);
     608  	printf(_("att_time=%-26.24s\n"),
     609  	       shmdata->shm_atim ? ctime64(&(shmdata->shm_atim)) : _("Not set"));
     610  	printf(_("det_time=%-26.24s\n"),
     611  	       shmdata->shm_dtim ? ctime64(&shmdata->shm_dtim) : _("Not set"));
     612  	printf(_("change_time=%-26.24s\n"), ctime64(&shmdata->shm_ctim));
     613  	printf("\n");
     614  
     615  	ipc_shm_free_info(shmdata);
     616  }
     617  
     618  static void print_msg(int msgid, int unit)
     619  {
     620  	struct msg_data *msgdata;
     621  
     622  	if (ipc_msg_get_info(msgid, &msgdata) < 1) {
     623  		warnx(_("id %d not found"), msgid);
     624  		return;
     625  	}
     626  
     627  	printf(_("\nMessage Queue msqid=%d\n"), msgid);
     628  	printf(_("uid=%u\tgid=%u\tcuid=%u\tcgid=%u\tmode=%#o\n"),
     629  	       msgdata->msg_perm.uid, msgdata->msg_perm.gid,
     630  	       msgdata->msg_perm.cuid, msgdata->msg_perm.cgid,
     631  	       msgdata->msg_perm.mode);
     632  	ipc_print_size(unit, unit == IPC_UNIT_HUMAN ? _("csize=") : _("cbytes="),
     633  		       msgdata->q_cbytes, "\t", 0);
     634  	ipc_print_size(unit, unit == IPC_UNIT_HUMAN ? _("qsize=") : _("qbytes="),
     635  		       msgdata->q_qbytes, "\t", 0);
     636  	printf("qnum=%jd\tlspid=%d\tlrpid=%d\n",
     637  	       msgdata->q_qnum,
     638  	       msgdata->q_lspid, msgdata->q_lrpid);
     639  	printf(_("send_time=%-26.24s\n"),
     640  	       msgdata->q_stime ? ctime64(&msgdata->q_stime) : _("Not set"));
     641  	printf(_("rcv_time=%-26.24s\n"),
     642  	       msgdata->q_rtime ? ctime64(&msgdata->q_rtime) : _("Not set"));
     643  	printf(_("change_time=%-26.24s\n"),
     644  	       msgdata->q_ctime ? ctime64(&msgdata->q_ctime) : _("Not set"));
     645  	printf("\n");
     646  
     647  	ipc_msg_free_info(msgdata);
     648  }
     649  
     650  static void print_sem(int semid)
     651  {
     652  	struct sem_data *semdata;
     653  	size_t i;
     654  
     655  	if (ipc_sem_get_info(semid, &semdata) < 1) {
     656  		warnx(_("id %d not found"), semid);
     657  		return;
     658  	}
     659  
     660  	printf(_("\nSemaphore Array semid=%d\n"), semid);
     661  	printf(_("uid=%u\t gid=%u\t cuid=%u\t cgid=%u\n"),
     662  	       semdata->sem_perm.uid, semdata->sem_perm.gid,
     663  	       semdata->sem_perm.cuid, semdata->sem_perm.cgid);
     664  	printf(_("mode=%#o, access_perms=%#o\n"),
     665  	       semdata->sem_perm.mode, semdata->sem_perm.mode & 0777);
     666  	printf(_("nsems = %ju\n"), semdata->sem_nsems);
     667  	printf(_("otime = %-26.24s\n"),
     668  	       semdata->sem_otime ? ctime64(&semdata->sem_otime) : _("Not set"));
     669  	printf(_("ctime = %-26.24s\n"), ctime64(&semdata->sem_ctime));
     670  
     671  	printf("%-10s %-10s %-10s %-10s %-10s\n",
     672  	       _("semnum"), _("value"), _("ncount"), _("zcount"), _("pid"));
     673  
     674  	for (i = 0; i < semdata->sem_nsems; i++) {
     675  		struct sem_elem *e = &semdata->elements[i];
     676  		printf("%-10zu %-10d %-10d %-10d %-10d\n",
     677  		       i, e->semval, e->ncount, e->zcount, e->pid);
     678  	}
     679  	printf("\n");
     680  	ipc_sem_free_info(semdata);
     681  }