(root)/
util-linux-2.39/
sys-utils/
ipcutils.c
       1  #include <inttypes.h>
       2  
       3  #include "c.h"
       4  #include "nls.h"
       5  #include "xalloc.h"
       6  #include "path.h"
       7  #include "pathnames.h"
       8  #include "ipcutils.h"
       9  #include "strutils.h"
      10  
      11  #ifndef SEMVMX
      12  # define SEMVMX  32767	/* <= 32767 semaphore maximum value */
      13  #endif
      14  #ifndef SHMMIN
      15  # define SHMMIN 1	/* min shared segment size in bytes */
      16  #endif
      17  
      18  
      19  int ipc_msg_get_limits(struct ipc_limits *lim)
      20  {
      21  	memset(lim, 0, sizeof(*lim));
      22  
      23  	if (access(_PATH_PROC_IPC_MSGMNI, F_OK) == 0 &&
      24  	    access(_PATH_PROC_IPC_MSGMNB, F_OK) == 0 &&
      25  	    access(_PATH_PROC_IPC_MSGMAX, F_OK) == 0) {
      26  
      27  		if (ul_path_read_s32(NULL, &lim->msgmni, _PATH_PROC_IPC_MSGMNI) != 0)
      28  			return 1;
      29  		if (ul_path_read_s32(NULL, &lim->msgmnb, _PATH_PROC_IPC_MSGMNB) != 0)
      30  			return 1;
      31  		if (ul_path_read_u64(NULL, &lim->msgmax, _PATH_PROC_IPC_MSGMAX) != 0)
      32  			return 1;
      33  	} else {
      34  		struct msginfo msginfo;
      35  
      36  		if (msgctl(0, IPC_INFO, (struct msqid_ds *) &msginfo) < 0)
      37  			return 1;
      38  		lim->msgmni = msginfo.msgmni;
      39  		lim->msgmnb = msginfo.msgmnb;
      40  		lim->msgmax = msginfo.msgmax;
      41  	}
      42  
      43  	return 0;
      44  }
      45  
      46  int ipc_sem_get_limits(struct ipc_limits *lim)
      47  {
      48  	FILE *f;
      49  	int rc = 0;
      50  
      51  	lim->semvmx = SEMVMX;
      52  
      53  	f = fopen(_PATH_PROC_IPC_SEM, "r");
      54  	if (f) {
      55  		rc = fscanf(f, "%d\t%d\t%d\t%d",
      56  		       &lim->semmsl, &lim->semmns, &lim->semopm, &lim->semmni);
      57  		fclose(f);
      58  	}
      59  
      60  	if (rc != 4) {
      61  		struct seminfo seminfo = { .semmni = 0 };
      62  		union semun arg = { .array = (ushort *) &seminfo };
      63  
      64  		if (semctl(0, 0, IPC_INFO, arg) < 0)
      65  			return 1;
      66  		lim->semmni = seminfo.semmni;
      67  		lim->semmsl = seminfo.semmsl;
      68  		lim->semmns = seminfo.semmns;
      69  		lim->semopm = seminfo.semopm;
      70  	}
      71  
      72  	return 0;
      73  }
      74  
      75  int ipc_shm_get_limits(struct ipc_limits *lim)
      76  {
      77  	lim->shmmin = SHMMIN;
      78  
      79  	if (access(_PATH_PROC_IPC_SHMALL, F_OK) == 0 &&
      80  	    access(_PATH_PROC_IPC_SHMMAX, F_OK) == 0 &&
      81  	    access(_PATH_PROC_IPC_SHMMNI, F_OK) == 0) {
      82  
      83  		ul_path_read_u64(NULL, &lim->shmall, _PATH_PROC_IPC_SHMALL);
      84  		ul_path_read_u64(NULL, &lim->shmmax, _PATH_PROC_IPC_SHMMAX);
      85  		ul_path_read_u64(NULL, &lim->shmmni, _PATH_PROC_IPC_SHMMNI);
      86  
      87  	} else {
      88  		struct shminfo *shminfo;
      89  		struct shmid_ds shmbuf;
      90  
      91  		if (shmctl(0, IPC_INFO, &shmbuf) < 0)
      92  			return 1;
      93  		shminfo = (struct shminfo *) &shmbuf;
      94  		lim->shmmni = shminfo->shmmni;
      95  		lim->shmall = shminfo->shmall;
      96  		lim->shmmax = shminfo->shmmax;
      97  	}
      98  
      99  	return 0;
     100  }
     101  
     102  int ipc_shm_get_info(int id, struct shm_data **shmds)
     103  {
     104  	FILE *f;
     105  	int i = 0, maxid, j;
     106  	char buf[BUFSIZ];
     107  	struct shm_data *p;
     108  	struct shmid_ds dummy;
     109  
     110  	p = *shmds = xcalloc(1, sizeof(struct shm_data));
     111  	p->next = NULL;
     112  
     113  	f = fopen(_PATH_PROC_SYSV_SHM, "r");
     114  	if (!f)
     115  		goto shm_fallback;
     116  
     117  	while (fgetc(f) != '\n');		/* skip header */
     118  
     119  	while (fgets(buf, sizeof(buf), f) != NULL) {
     120  		/* scan for the first 14-16 columns (e.g. Linux 2.6.32 has 14) */
     121  		p->shm_rss = 0xdead;
     122  		p->shm_swp = 0xdead;
     123  		if (sscanf(buf,
     124  			  "%d %d  %o %"SCNu64 " %u %u  "
     125  			  "%"SCNu64 " %u %u %u %u %"SCNi64 " %"SCNi64 " %"SCNi64
     126  			  " %"SCNu64 " %"SCNu64 "\n",
     127  			   &p->shm_perm.key,
     128  			   &p->shm_perm.id,
     129  			   &p->shm_perm.mode,
     130  			   &p->shm_segsz,
     131  			   &p->shm_cprid,
     132  			   &p->shm_lprid,
     133  			   &p->shm_nattch,
     134  			   &p->shm_perm.uid,
     135  			   &p->shm_perm.gid,
     136  			   &p->shm_perm.cuid,
     137  			   &p->shm_perm.cgid,
     138  			   &p->shm_atim,
     139  			   &p->shm_dtim,
     140  			   &p->shm_ctim,
     141  			   &p->shm_rss,
     142  			   &p->shm_swp) < 14)
     143  			continue; /* invalid line, skipped */
     144  
     145  		if (id > -1) {
     146  			/* ID specified */
     147  			if (id == p->shm_perm.id) {
     148  				i = 1;
     149  				break;
     150  			}
     151  			continue;
     152  		}
     153  
     154  		p->next = xcalloc(1, sizeof(struct shm_data));
     155  		p = p->next;
     156  		p->next = NULL;
     157  		i++;
     158  	}
     159  
     160  	if (i == 0)
     161  		free(*shmds);
     162  	fclose(f);
     163  	return i;
     164  
     165  	/* Fallback; /proc or /sys file(s) missing. */
     166  shm_fallback:
     167  	maxid = shmctl(0, SHM_INFO, &dummy);
     168  
     169  	for (j = 0; j <= maxid; j++) {
     170  		int shmid;
     171  		struct shmid_ds shmseg;
     172  		struct ipc_perm *ipcp = &shmseg.shm_perm;
     173  
     174  		shmid = shmctl(j, SHM_STAT, &shmseg);
     175  		if (shmid < 0 || (id > -1 && shmid != id)) {
     176  			continue;
     177  		}
     178  
     179  		i++;
     180  		p->shm_perm.key = ipcp->KEY;
     181  		p->shm_perm.id = shmid;
     182  		p->shm_perm.mode = ipcp->mode;
     183  		p->shm_segsz = shmseg.shm_segsz;
     184  		p->shm_cprid = shmseg.shm_cpid;
     185  		p->shm_lprid = shmseg.shm_lpid;
     186  		p->shm_nattch = shmseg.shm_nattch;
     187  		p->shm_perm.uid = ipcp->uid;
     188  		p->shm_perm.gid = ipcp->gid;
     189  		p->shm_perm.cuid = ipcp->cuid;
     190  		p->shm_perm.cgid = ipcp->cuid;
     191  		p->shm_atim = shmseg.shm_atime;
     192  		p->shm_dtim = shmseg.shm_dtime;
     193  		p->shm_ctim = shmseg.shm_ctime;
     194  		p->shm_rss = 0xdead;
     195  		p->shm_swp = 0xdead;
     196  
     197  		if (id < 0) {
     198  			p->next = xcalloc(1, sizeof(struct shm_data));
     199  			p = p->next;
     200  			p->next = NULL;
     201  		} else
     202  			break;
     203  	}
     204  
     205  	if (i == 0)
     206  		free(*shmds);
     207  	return i;
     208  }
     209  
     210  void ipc_shm_free_info(struct shm_data *shmds)
     211  {
     212  	while (shmds) {
     213  		struct shm_data *next = shmds->next;
     214  		free(shmds);
     215  		shmds = next;
     216  	}
     217  }
     218  
     219  static void get_sem_elements(struct sem_data *p)
     220  {
     221  	size_t i;
     222  
     223  	if (!p || !p->sem_nsems || p->sem_nsems > SIZE_MAX || p->sem_perm.id < 0)
     224  		return;
     225  
     226  	p->elements = xcalloc(p->sem_nsems, sizeof(struct sem_elem));
     227  
     228  	for (i = 0; i < p->sem_nsems; i++) {
     229  		struct sem_elem *e = &p->elements[i];
     230  		union semun arg = { .val = 0 };
     231  
     232  		e->semval = semctl(p->sem_perm.id, i, GETVAL, arg);
     233  		if (e->semval < 0)
     234  			err(EXIT_FAILURE, _("%s failed"), "semctl(GETVAL)");
     235  
     236  		e->ncount = semctl(p->sem_perm.id, i, GETNCNT, arg);
     237  		if (e->ncount < 0)
     238  			err(EXIT_FAILURE, _("%s failed"), "semctl(GETNCNT)");
     239  
     240  		e->zcount = semctl(p->sem_perm.id, i, GETZCNT, arg);
     241  		if (e->zcount < 0)
     242  			err(EXIT_FAILURE, _("%s failed"), "semctl(GETZCNT)");
     243  
     244  		e->pid = semctl(p->sem_perm.id, i, GETPID, arg);
     245  		if (e->pid < 0)
     246  			err(EXIT_FAILURE, _("%s failed"), "semctl(GETPID)");
     247  	}
     248  }
     249  
     250  int ipc_sem_get_info(int id, struct sem_data **semds)
     251  {
     252  	FILE *f;
     253  	int i = 0, maxid, j;
     254  	struct sem_data *p;
     255  	struct seminfo dummy;
     256  	union semun arg;
     257  
     258  	p = *semds = xcalloc(1, sizeof(struct sem_data));
     259  	p->next = NULL;
     260  
     261  	f = fopen(_PATH_PROC_SYSV_SEM, "r");
     262  	if (!f)
     263  		goto sem_fallback;
     264  
     265  	while (fgetc(f) != '\n') ;	/* skip header */
     266  
     267  	while (feof(f) == 0) {
     268  		if (fscanf(f,
     269  			   "%d %d  %o %" SCNu64 " %u %u %u %u %"
     270  			    SCNi64 " %" SCNi64 "\n",
     271  			   &p->sem_perm.key,
     272  			   &p->sem_perm.id,
     273  			   &p->sem_perm.mode,
     274  			   &p->sem_nsems,
     275  			   &p->sem_perm.uid,
     276  			   &p->sem_perm.gid,
     277  			   &p->sem_perm.cuid,
     278  			   &p->sem_perm.cgid,
     279  			   &p->sem_otime,
     280  			   &p->sem_ctime) != 10)
     281  			continue;
     282  
     283  		if (id > -1) {
     284  			/* ID specified */
     285  			if (id == p->sem_perm.id) {
     286  				get_sem_elements(p);
     287  				i = 1;
     288  				break;
     289  			}
     290  			continue;
     291  		}
     292  
     293  		p->next = xcalloc(1, sizeof(struct sem_data));
     294  		p = p->next;
     295  		p->next = NULL;
     296  		i++;
     297  	}
     298  
     299  	if (i == 0)
     300  		free(*semds);
     301  	fclose(f);
     302  	return i;
     303  
     304  	/* Fallback; /proc or /sys file(s) missing. */
     305  sem_fallback:
     306  	arg.array = (ushort *) (void *)&dummy;
     307  	maxid = semctl(0, 0, SEM_INFO, arg);
     308  
     309  	for (j = 0; j <= maxid; j++) {
     310  		int semid;
     311  		struct semid_ds semseg;
     312  		struct ipc_perm *ipcp = &semseg.sem_perm;
     313  		arg.buf = (struct semid_ds *)&semseg;
     314  
     315  		semid = semctl(j, 0, SEM_STAT, arg);
     316  		if (semid < 0 || (id > -1 && semid != id)) {
     317  			continue;
     318  		}
     319  
     320  		i++;
     321  		p->sem_perm.key = ipcp->KEY;
     322  		p->sem_perm.id = semid;
     323  		p->sem_perm.mode = ipcp->mode;
     324  		p->sem_nsems = semseg.sem_nsems;
     325  		p->sem_perm.uid = ipcp->uid;
     326  		p->sem_perm.gid = ipcp->gid;
     327  		p->sem_perm.cuid = ipcp->cuid;
     328  		p->sem_perm.cgid = ipcp->cuid;
     329  		p->sem_otime = semseg.sem_otime;
     330  		p->sem_ctime = semseg.sem_ctime;
     331  
     332  		if (id < 0) {
     333  			p->next = xcalloc(1, sizeof(struct sem_data));
     334  			p = p->next;
     335  			p->next = NULL;
     336  			i++;
     337  		} else {
     338  			get_sem_elements(p);
     339  			break;
     340  		}
     341  	}
     342  
     343  	if (i == 0)
     344  		free(*semds);
     345  	return i;
     346  }
     347  
     348  void ipc_sem_free_info(struct sem_data *semds)
     349  {
     350  	while (semds) {
     351  		struct sem_data *next = semds->next;
     352  		free(semds->elements);
     353  		free(semds);
     354  		semds = next;
     355  	}
     356  }
     357  
     358  int ipc_msg_get_info(int id, struct msg_data **msgds)
     359  {
     360  	FILE *f;
     361  	int i = 0, maxid, j;
     362  	struct msg_data *p;
     363  	struct msqid_ds dummy;
     364  	struct msqid_ds msgseg;
     365  
     366  	p = *msgds = xcalloc(1, sizeof(struct msg_data));
     367  	p->next = NULL;
     368  
     369  	f = fopen(_PATH_PROC_SYSV_MSG, "r");
     370  	if (!f)
     371  		goto msg_fallback;
     372  
     373  	while (fgetc(f) != '\n') ;	/* skip header */
     374  
     375  	while (feof(f) == 0) {
     376  		if (fscanf(f,
     377  			   "%d %d  %o  %" SCNu64 " %" SCNu64
     378  			   " %u %u %u %u %u %u %" SCNi64 " %" SCNi64 " %" SCNi64 "\n",
     379  			   &p->msg_perm.key,
     380  			   &p->msg_perm.id,
     381  			   &p->msg_perm.mode,
     382  			   &p->q_cbytes,
     383  			   &p->q_qnum,
     384  			   &p->q_lspid,
     385  			   &p->q_lrpid,
     386  			   &p->msg_perm.uid,
     387  			   &p->msg_perm.gid,
     388  			   &p->msg_perm.cuid,
     389  			   &p->msg_perm.cgid,
     390  			   &p->q_stime,
     391  			   &p->q_rtime,
     392  			   &p->q_ctime) != 14)
     393  			continue;
     394  
     395  		if (id > -1) {
     396  			/* ID specified */
     397  			if (id == p->msg_perm.id) {
     398  				if (msgctl(id, IPC_STAT, &msgseg) != -1)
     399  					p->q_qbytes = msgseg.msg_qbytes;
     400  				i = 1;
     401  				break;
     402  			}
     403  			continue;
     404  		}
     405  
     406  		p->next = xcalloc(1, sizeof(struct msg_data));
     407  		p = p->next;
     408  		p->next = NULL;
     409  		i++;
     410  	}
     411  
     412  	if (i == 0)
     413  		free(*msgds);
     414  	fclose(f);
     415  	return i;
     416  
     417  	/* Fallback; /proc or /sys file(s) missing. */
     418  msg_fallback:
     419  	maxid = msgctl(0, MSG_INFO, &dummy);
     420  
     421  	for (j = 0; j <= maxid; j++) {
     422  		int msgid;
     423  		struct ipc_perm *ipcp = &msgseg.msg_perm;
     424  
     425  		msgid = msgctl(j, MSG_STAT, &msgseg);
     426  		if (msgid < 0 || (id > -1 && msgid != id)) {
     427  			continue;
     428  		}
     429  
     430  		i++;
     431  		p->msg_perm.key = ipcp->KEY;
     432  		p->msg_perm.id = msgid;
     433  		p->msg_perm.mode = ipcp->mode;
     434  		p->q_cbytes = msgseg.msg_cbytes;
     435  		p->q_qnum = msgseg.msg_qnum;
     436  		p->q_lspid = msgseg.msg_lspid;
     437  		p->q_lrpid = msgseg.msg_lrpid;
     438  		p->msg_perm.uid = ipcp->uid;
     439  		p->msg_perm.gid = ipcp->gid;
     440  		p->msg_perm.cuid = ipcp->cuid;
     441  		p->msg_perm.cgid = ipcp->cgid;
     442  		p->q_stime = msgseg.msg_stime;
     443  		p->q_rtime = msgseg.msg_rtime;
     444  		p->q_ctime = msgseg.msg_ctime;
     445  		p->q_qbytes = msgseg.msg_qbytes;
     446  
     447  		if (id < 0) {
     448  			p->next = xcalloc(1, sizeof(struct msg_data));
     449  			p = p->next;
     450  			p->next = NULL;
     451  		} else
     452  			break;
     453  	}
     454  
     455  	if (i == 0)
     456  		free(*msgds);
     457  	return i;
     458  }
     459  
     460  void ipc_msg_free_info(struct msg_data *msgds)
     461  {
     462  	while (msgds) {
     463  		struct msg_data *next = msgds->next;
     464  		free(msgds);
     465  		msgds = next;
     466  	}
     467  }
     468  
     469  void ipc_print_perms(FILE *f, struct ipc_stat *is)
     470  {
     471  	struct passwd *pw;
     472  	struct group *gr;
     473  
     474  	fprintf(f, "%-10d %-10o", is->id, is->mode & 0777);
     475  
     476  	if ((pw = getpwuid(is->cuid)))
     477  		fprintf(f, " %-10s", pw->pw_name);
     478  	else
     479  		fprintf(f, " %-10u", is->cuid);
     480  
     481  	if ((gr = getgrgid(is->cgid)))
     482  		fprintf(f, " %-10s", gr->gr_name);
     483  	else
     484  		fprintf(f, " %-10u", is->cgid);
     485  
     486  	if ((pw = getpwuid(is->uid)))
     487  		fprintf(f, " %-10s", pw->pw_name);
     488  	else
     489  		fprintf(f, " %-10u", is->uid);
     490  
     491  	if ((gr = getgrgid(is->gid)))
     492  		fprintf(f, " %-10s\n", gr->gr_name);
     493  	else
     494  		fprintf(f, " %-10u\n", is->gid);
     495  }
     496  
     497  void ipc_print_size(int unit, char *msg, uint64_t size, const char *end,
     498  		    int width)
     499  {
     500  	char format[32];
     501  
     502  	if (!msg)
     503  		/* NULL */ ;
     504  	else if (msg[strlen(msg) - 1] == '=')
     505  		printf("%s", msg);
     506  	else if (unit == IPC_UNIT_BYTES)
     507  		printf(_("%s (bytes) = "), msg);
     508  	else if (unit == IPC_UNIT_KB)
     509  		printf(_("%s (kbytes) = "), msg);
     510  	else
     511  		printf("%s = ", msg);
     512  
     513  	switch (unit) {
     514  	case IPC_UNIT_DEFAULT:
     515  	case IPC_UNIT_BYTES:
     516  		snprintf(format, sizeof(format), "%%%dju", width);
     517  		printf(format, size);
     518  		break;
     519  	case IPC_UNIT_KB:
     520  		snprintf(format, sizeof(format), "%%%dju", width);
     521  		printf(format, size / 1024);
     522  		break;
     523  	case IPC_UNIT_HUMAN:
     524  	{
     525  		char *tmp;
     526  		snprintf(format, sizeof(format), "%%%ds", width);
     527  		printf(format, (tmp = size_to_human_string(SIZE_SUFFIX_1LETTER, size)));
     528  		free(tmp);
     529  		break;
     530  	}
     531  	default:
     532  		/* impossible occurred */
     533  		abort();
     534  	}
     535  
     536  	if (end)
     537  		printf("%s", end);
     538  }