Exemple #1
0
/*===========================================================================*
 *				do_shmdt		     		     *
 *===========================================================================*/
PUBLIC int do_shmdt(message *m)
{
	vir_bytes addr;
	phys_bytes paddr;
	int i;

	addr = m->SHMDT_ADDR;

	if ((paddr = vm_getphys(who_e, (void *) addr)) == 0)
		return EINVAL;

	for (i = 0; i < shm_list_nr; i++) {
		if (shm_list[i].phys == paddr) {
			struct shm_struct *shm = &shm_list[i];

			shm->shmid_ds.shm_atime = time(NULL);
			shm->shmid_ds.shm_lpid = getnpid(who_e);
			/* nattch is updated lazily */

			vm_unmap(who_e, (void *) addr);
			break;
		}
	}
	if (i == shm_list_nr)
		fprintf(stderr, "IPC: do_shmdt impossible error!\n");

	update_refcount_and_destroy();

	return OK;
}
Exemple #2
0
/*===========================================================================*
 *				do_shmdt		     		     *
 *===========================================================================*/
int do_shmdt(message *m)
{
	vir_bytes addr;
	phys_bytes vm_id;
	int i;

	addr = (vir_bytes) m->m_lc_ipc_shmdt.addr;

	if ((vm_id = vm_getphys(who_e, (void *) addr)) == 0)
		return EINVAL;

	for (i = 0; i < shm_list_nr; i++) {
		if (shm_list[i].vm_id == vm_id) {
			struct shm_struct *shm = &shm_list[i];

			shm->shmid_ds.shm_atime = time(NULL);
			shm->shmid_ds.shm_lpid = getnpid(who_e);
			/* nattch is updated lazily */

			vm_unmap(who_e, (void *) addr);
			break;
		}
	}
	if (i == shm_list_nr)
		printf("IPC: do_shmdt impossible error! could not find id %lu to unmap\n",
			vm_id);

	update_refcount_and_destroy();

	return OK;
}
Exemple #3
0
/*===========================================================================*
 *				init_server                                  *
 *===========================================================================*/
PRIVATE void init_server(void)
{
/* Initialize the reincarnation server. */
  struct sigaction sa;
  struct boot_image *ip;
  int s,t;

  /* Install signal handlers. Ask PM to transform signal into message. */
  sa.sa_handler = SIG_MESS;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  if (sigaction(SIGCHLD,&sa,NULL)<0) panic("RS","sigaction failed", errno);
  if (sigaction(SIGTERM,&sa,NULL)<0) panic("RS","sigaction failed", errno);

  /* Initialize the system process table. Use the boot image from the kernel
   * and the device map from the FS to gather all needed information.
   */
  if ((s = sys_getimage(image)) != OK) 
      panic("RS","warning: couldn't get copy of image table", s);
  if ((s = getsysinfo(FS_PROC_NR, SI_DMAP_TAB, dmap)) < 0)
      panic("RS","warning: couldn't get copy of dmap table", errno);
  
  /* Now initialize the table with the processes in the system image. 
   * Prepend /sbin/ to the binaries so that we can actually find them. 
   */
  for (s=0; s< NR_BOOT_PROCS; s++) {
      ip = &image[s];
      if (ip->proc_nr >= 0) {
          nr_in_use ++;
          rproc[s].r_flags = RS_IN_USE;
          rproc[s].r_proc_nr_e = ip->endpoint;
          rproc[s].r_pid = getnpid(ip->proc_nr);
	  for(t=0; t< NR_DEVICES; t++)
	      if (dmap[t].dmap_driver == ip->proc_nr)
                  rproc[s].r_dev_nr = t;
	  strcpy(rproc[s].r_cmd, "/sbin/");
          strcpy(rproc[s].r_cmd+6, ip->proc_name);
          rproc[s].r_argc = 1;
          rproc[s].r_argv[0] = rproc[s].r_cmd;
          rproc[s].r_argv[1] = NULL;
      }
  }

  /* Set alarm to periodically check driver status. */
  if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
      panic("RS", "couldn't set alarm", s);

}
Exemple #4
0
/*===========================================================================*
 *				do_shmat		     		     *
 *===========================================================================*/
PUBLIC int do_shmat(message *m)
{
	int id, flag;
	vir_bytes addr;
	void *ret;
	struct shm_struct *shm;

	id = m->SHMAT_ID;
	addr = (vir_bytes) m->SHMAT_ADDR;
	flag = m->SHMAT_FLAG;

	if (addr && (addr % I386_PAGE_SIZE)) {
		if (flag & SHM_RND)
			addr -= (addr % I386_PAGE_SIZE);
		else
			return EINVAL;
	}

	if (!(shm = shm_find_id(id)))
		return EINVAL;

	if (flag & SHM_RDONLY)
		flag = 0444;
	else
		flag = 0666;
	if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag))
		return EACCES;

	ret = vm_remap(who_e, SELF_E, (void *)addr, (void *)shm->page,
			shm->shmid_ds.shm_segsz);
	if (ret == MAP_FAILED)
		return ENOMEM;

	shm->shmid_ds.shm_atime = time(NULL);
	shm->shmid_ds.shm_lpid = getnpid(who_e);
	/* nattach is updated lazily */

	m->SHMAT_RETADDR = (long) ret;
	return OK;
}
Exemple #5
0
/*===========================================================================*
 *				do_shmat		     		     *
 *===========================================================================*/
int do_shmat(message *m)
{
	int id, flag;
	vir_bytes addr;
	void *ret;
	struct shm_struct *shm;

	id = m->m_lc_ipc_shmat.id;
	addr = (vir_bytes) m->m_lc_ipc_shmat.addr;
	flag = m->m_lc_ipc_shmat.flag;

	if (addr && (addr % PAGE_SIZE)) {
		if (flag & SHM_RND)
			addr -= (addr % PAGE_SIZE);
		else
			return EINVAL;
	}

	if (!(shm = shm_find_id(id)))
		return EINVAL;

	if (flag & SHM_RDONLY)
		flag = 0444;
	else
		flag = 0666;
	if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag))
		return EACCES;

	ret = vm_remap(who_e, sef_self(), (void *)addr, (void *)shm->page,
			shm->shmid_ds.shm_segsz);
	if (ret == MAP_FAILED)
		return ENOMEM;

	shm->shmid_ds.shm_atime = time(NULL);
	shm->shmid_ds.shm_lpid = getnpid(who_e);
	/* nattach is updated lazily */

	m->m_lc_ipc_shmat.retaddr = ret;
	return OK;
}
Exemple #6
0
/*===========================================================================*
 *		            sef_cb_init_fresh                                *
 *===========================================================================*/
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
{
/* Initialize the reincarnation server. */
  struct boot_image *ip;
  int s,i;
  int nr_image_srvs, nr_image_priv_srvs, nr_uncaught_init_srvs;
  struct rproc *rp;
  struct rproc *replica_rp;
  struct rprocpub *rpub;
  struct boot_image image[NR_BOOT_PROCS];
  struct boot_image_priv *boot_image_priv;
  struct boot_image_sys *boot_image_sys;
  struct boot_image_dev *boot_image_dev;
  int pid, replica_pid;
  endpoint_t replica_endpoint;
  int ipc_to;
  int *calls;
  int all_c[] = { ALL_C, NULL_C };
  int no_c[] = {  NULL_C };

  /* See if we run in verbose mode. */
  env_parse("rs_verbose", "d", 0, &rs_verbose, 0, 1);

  if ((s = sys_getinfo(GET_HZ, &system_hz, sizeof(system_hz), 0, 0)) != OK)
	  panic("Cannot get system timer frequency\n");

  /* Initialize the global init descriptor. */
  rinit.rproctab_gid = cpf_grant_direct(ANY, (vir_bytes) rprocpub,
      sizeof(rprocpub), CPF_READ);
  if(!GRANT_VALID(rinit.rproctab_gid)) {
      panic("unable to create rprocpub table grant: %d", rinit.rproctab_gid);
  }

  /* Initialize some global variables. */
  rupdate.flags = 0;
  shutting_down = FALSE;

  /* Get a copy of the boot image table. */
  if ((s = sys_getimage(image)) != OK) {
      panic("unable to get copy of boot image table: %d", s);
  }

  /* Determine the number of system services in the boot image table. */
  nr_image_srvs = 0;
  for(i=0;i<NR_BOOT_PROCS;i++) {
      ip = &image[i];

      /* System services only. */
      if(iskerneln(_ENDPOINT_P(ip->endpoint))) {
          continue;
      }
      nr_image_srvs++;
  }

  /* Determine the number of entries in the boot image priv table and make sure
   * it matches the number of system services in the boot image table.
   */
  nr_image_priv_srvs = 0;
  for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
      boot_image_priv = &boot_image_priv_table[i];

      /* System services only. */
      if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
          continue;
      }
      nr_image_priv_srvs++;
  }
  if(nr_image_srvs != nr_image_priv_srvs) {
	panic("boot image table and boot image priv table mismatch");
  }

  /* Reset the system process table. */
  for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
      rp->r_flags = 0;
      rp->r_pub = &rprocpub[rp - rproc];
      rp->r_pub->in_use = FALSE;
  }

  /* Initialize the system process table in 4 steps, each of them following
   * the appearance of system services in the boot image priv table.
   * - Step 1: set priviliges, sys properties, and dev properties (if any)
   * for every system service.
   */
  for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
      boot_image_priv = &boot_image_priv_table[i];

      /* System services only. */
      if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
          continue;
      }

      /* Lookup the corresponding entries in other tables. */
      boot_image_info_lookup(boot_image_priv->endpoint, image,
          &ip, NULL, &boot_image_sys, &boot_image_dev);
      rp = &rproc[boot_image_priv - boot_image_priv_table];
      rpub = rp->r_pub;

      /*
       * Set privileges.
       */
      /* Get label. */
      strcpy(rpub->label, boot_image_priv->label);

      /* Force a static priv id for system services in the boot image. */
      rp->r_priv.s_id = static_priv_id(
          _ENDPOINT_P(boot_image_priv->endpoint));
      
      /* Initialize privilege bitmaps and signal manager. */
      rp->r_priv.s_flags = boot_image_priv->flags;          /* priv flags */
      rp->r_priv.s_trap_mask= SRV_OR_USR(rp, SRV_T, USR_T); /* traps */
      ipc_to = SRV_OR_USR(rp, SRV_M, USR_M);                /* targets */
      fill_send_mask(&rp->r_priv.s_ipc_to, ipc_to == ALL_M);
      rp->r_priv.s_sig_mgr= SRV_OR_USR(rp, SRV_SM, USR_SM); /* sig mgr */
      rp->r_priv.s_bak_sig_mgr = NONE;                      /* backup sig mgr */
      
      /* Initialize kernel call mask bitmap. */
      calls = SRV_OR_USR(rp, SRV_KC, USR_KC) == ALL_C ? all_c : no_c;
      fill_call_mask(calls, NR_SYS_CALLS,
          rp->r_priv.s_k_call_mask, KERNEL_CALL, TRUE);

      /* Set the privilege structure. */
      if(boot_image_priv->endpoint != RS_PROC_NR) {
          if ((s = sys_privctl(ip->endpoint, SYS_PRIV_SET_SYS, &(rp->r_priv)))
              != OK) {
              panic("unable to set privilege structure: %d", s);
          }
      }

      /* Synch the privilege structure with the kernel. */
      if ((s = sys_getpriv(&(rp->r_priv), ip->endpoint)) != OK) {
          panic("unable to synch privilege structure: %d", s);
      }

      /*
       * Set sys properties.
       */
      rpub->sys_flags = boot_image_sys->flags;        /* sys flags */

      /*
       * Set dev properties.
       */
      rpub->dev_flags = boot_image_dev->flags;        /* device flags */
      rpub->dev_nr = boot_image_dev->dev_nr;          /* major device number */
      rpub->dev_style = boot_image_dev->dev_style;    /* device style */
      rpub->dev_style2 = boot_image_dev->dev_style2;  /* device style 2 */

      /* Get process name. */
      strcpy(rpub->proc_name, ip->proc_name);

      /* Build command settings. */
      rp->r_cmd[0]= '\0';
      rp->r_script[0]= '\0';
      build_cmd_dep(rp);

      /* Initialize vm call mask bitmap. */
      calls = SRV_OR_USR(rp, SRV_VC, USR_VC) == ALL_C ? all_c : no_c;
      fill_call_mask(calls, NR_VM_CALLS, rpub->vm_call_mask, VM_RQ_BASE, TRUE);

      /* Scheduling parameters. */
      rp->r_scheduler = SRV_OR_USR(rp, SRV_SCH, USR_SCH);
      rp->r_priority = SRV_OR_USR(rp, SRV_Q, USR_Q);
      rp->r_quantum = SRV_OR_USR(rp, SRV_QT, USR_QT);

      /* Get some settings from the boot image table. */
      rpub->endpoint = ip->endpoint;

      /* Set some defaults. */
      rp->r_old_rp = NULL;                     /* no old version yet */
      rp->r_new_rp = NULL;                     /* no new version yet */
      rp->r_prev_rp = NULL;                    /* no prev replica yet */
      rp->r_next_rp = NULL;                    /* no next replica yet */
      rp->r_uid = 0;                           /* root */
      rp->r_check_tm = 0;                      /* not checked yet */
      getuptime(&rp->r_alive_tm);              /* currently alive */
      rp->r_stop_tm = 0;                       /* not exiting yet */
      rp->r_restarts = 0;                      /* no restarts so far */
      rp->r_period = 0;                        /* no period yet */
      rp->r_exec = NULL;                       /* no in-memory copy yet */
      rp->r_exec_len = 0;

      /* Mark as in use and active. */
      rp->r_flags = RS_IN_USE | RS_ACTIVE;
      rproc_ptr[_ENDPOINT_P(rpub->endpoint)]= rp;
      rpub->in_use = TRUE;
  }

  /* - Step 2: allow every system service in the boot image to run. */
  nr_uncaught_init_srvs = 0;
  for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
      boot_image_priv = &boot_image_priv_table[i];

      /* System services only. */
      if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
          continue;
      }

      /* Lookup the corresponding slot in the system process table. */
      rp = &rproc[boot_image_priv - boot_image_priv_table];
      rpub = rp->r_pub;

      /* RS is already running as we speak. */
      if(boot_image_priv->endpoint == RS_PROC_NR) {
          if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) {
              panic("unable to initialize RS: %d", s);
          }
          continue;
      }

      /* Allow the service to run. */
      if ((s = sched_init_proc(rp)) != OK) {
          panic("unable to initialize scheduling: %d", s);
      }
      if ((s = sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
          panic("unable to initialize privileges: %d", s);
      }

      /* Initialize service. We assume every service will always get
       * back to us here at boot time.
       */
      if(boot_image_priv->flags & SYS_PROC) {
          if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) {
              panic("unable to initialize service: %d", s);
          }
          if(rpub->sys_flags & SF_SYNCH_BOOT) {
              /* Catch init ready message now to synchronize. */
              catch_boot_init_ready(rpub->endpoint);
          }
          else {
              /* Catch init ready message later. */
              nr_uncaught_init_srvs++;
          }
      }
  }

  /* - Step 3: let every system service complete initialization by
   * catching all the init ready messages left.
   */
  while(nr_uncaught_init_srvs) {
      catch_boot_init_ready(ANY);
      nr_uncaught_init_srvs--;
  }

  /* - Step 4: all the system services in the boot image are now running.
   * Complete the initialization of the system process table in collaboration
   * with other system services.
   */
  for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
      boot_image_priv = &boot_image_priv_table[i];

      /* System services only. */
      if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
          continue;
      }

      /* Lookup the corresponding slot in the system process table. */
      rp = &rproc[boot_image_priv - boot_image_priv_table];
      rpub = rp->r_pub;

      /* Get pid from PM. */
      rp->r_pid = getnpid(rpub->endpoint);
      if(rp->r_pid == -1) {
          panic("unable to get pid");
      }
  }

  /* Set alarm to periodically check service status. */
  if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
      panic("couldn't set alarm: %d", s);

  /* Now create a new RS instance with a private page table and let the current
   * instance live update into the replica. Clone RS' own slot first.
   */
  rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
  if((s = clone_slot(rp, &replica_rp)) != OK) {
      panic("unable to clone current RS instance: %d", s);
  }

  /* Fork a new RS instance. */
  pid = srv_fork();
  if(pid == -1) {
      panic("unable to fork a new RS instance");
  }
  replica_pid = pid ? pid : getpid();
  replica_endpoint = getnprocnr(replica_pid);
  replica_rp->r_pid = replica_pid;
  replica_rp->r_pub->endpoint = replica_endpoint;

  if(pid == 0) {
      /* New RS instance running. */

      /* Live update the old instance into the new one. */
      s = update_service(&rp, &replica_rp, RS_SWAP);
      if(s != OK) {
          panic("unable to live update RS: %d", s);
      }
      cpf_reload();

      /* Clean up the old RS instance, the new instance will take over. */
      cleanup_service(rp);

      /* Map out our own text and data. */
      unmap_ok = 1;
      _minix_unmapzero();

      /* Ask VM to pin memory for the new RS instance. */
      if((s = vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN)) != OK) {
          panic("unable to pin memory for the new RS instance: %d", s);
      }
  }
  else {
      /* Old RS instance running. */

      /* Set up privileges for the new instance and let it run. */
      s = sys_privctl(replica_endpoint, SYS_PRIV_SET_SYS, &(replica_rp->r_priv));
      if(s != OK) {
          panic("unable to set privileges for the new RS instance: %d", s);
      }
      if ((s = sched_init_proc(replica_rp)) != OK) {
          panic("unable to initialize RS replica scheduling: %d", s);
      }
      s = sys_privctl(replica_endpoint, SYS_PRIV_YIELD, NULL);
      if(s != OK) {
          panic("unable to yield control to the new RS instance: %d", s);
      }
      NOT_REACHABLE;
  }

  return(OK);
}
Exemple #7
0
/*===========================================================================*
 *				do_shmget		     		     *
 *===========================================================================*/
PUBLIC int do_shmget(message *m)
{
	struct shm_struct *shm;
	long key, size, old_size;
	int flag;
	int id;

	key = m->SHMGET_KEY;
	old_size = size = m->SHMGET_SIZE;
	flag = m->SHMGET_FLAG;

	if ((shm = shm_find_key(key))) {
		if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag))
			return EACCES;
		if ((flag & IPC_CREAT) && (flag & IPC_EXCL))
			return EEXIST;
		if (size && shm->shmid_ds.shm_segsz < size)
			return EINVAL;
		id = shm->id;
	} else { /* no key found */
		if (!(flag & IPC_CREAT))
			return ENOENT;
		if (size <= 0)
			return EINVAL;
		/* round up to a multiple of PAGE_SIZE */
		if (size % I386_PAGE_SIZE)
			size += I386_PAGE_SIZE - size % I386_PAGE_SIZE;
		if (size <= 0)
			return EINVAL;

		if (shm_list_nr == MAX_SHM_NR)
			return ENOMEM;
		/* TODO: shmmni should be changed... */
		if (identifier == SHMMNI)
			return ENOSPC;
		shm = &shm_list[shm_list_nr];
		memset(shm, 0, sizeof(struct shm_struct));
		shm->page = (vir_bytes) mmap(0, size,
					PROT_READ|PROT_WRITE,
					MAP_CONTIG|MAP_PREALLOC|MAP_ANON|MAP_SHARED,
					-1, 0);
		if (shm->page == (vir_bytes) MAP_FAILED)
			return ENOMEM;
		shm->phys = vm_getphys(SELF_E, (void *) shm->page);
		memset((void *)shm->page, 0, size);

		shm->shmid_ds.shm_perm.cuid =
			shm->shmid_ds.shm_perm.uid = getnuid(who_e);
		shm->shmid_ds.shm_perm.cgid =
			shm->shmid_ds.shm_perm.gid = getngid(who_e);
		shm->shmid_ds.shm_perm.mode = flag & 0777;
		shm->shmid_ds.shm_segsz = old_size;
		shm->shmid_ds.shm_atime = 0;
		shm->shmid_ds.shm_dtime = 0;
		shm->shmid_ds.shm_ctime = time(NULL);
		shm->shmid_ds.shm_cpid = getnpid(who_e);
		shm->shmid_ds.shm_lpid = 0;
		shm->shmid_ds.shm_nattch = 0;
		shm->id = id = identifier++;
		shm->key = key;

		shm_list_nr++;
	}

	m->SHMGET_RETID = id;
	return OK;
}
Exemple #8
0
/*===========================================================================*
 *				do_semop		     		     *
 *===========================================================================*/
PUBLIC int do_semop(message *m)
{
	int id, i, j, r;
	struct sembuf *sops;
	unsigned int nsops;
	struct sem_struct *sem;
	int no_reply = 0;

	id = m->SEMOP_ID;
	nsops = (unsigned int) m->SEMOP_SIZE;

	r = EINVAL;
	if (!(sem = sem_find_id(id)))
		goto out;

	if (nsops <= 0)
		goto out;

	r = E2BIG;
	if (nsops > SEMOPM)
		goto out;

	/* check for read permission */
	r = EACCES;
	if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444))
		goto out;

	/* get the array from user application */
	r = ENOMEM;
	sops = malloc(sizeof(struct sembuf) * nsops);
	if (!sops)
		goto out_free;
	r = sys_datacopy(who_e, (vir_bytes) m->SEMOP_OPS,
			SELF_E, (vir_bytes) sops,
			sizeof(struct sembuf) * nsops);
	if (r != OK) {
		r = EINVAL;
		goto out_free;
	}

#ifdef DEBUG_SEM
	for (i = 0; i < nsops; i++)
		printf("SEMOP: num:%d  op:%d  flg:%d\n",
			sops[i].sem_num, sops[i].sem_op, sops[i].sem_flg);
#endif
	/* check for value range */
	r = EFBIG;
	for (i = 0; i < nsops; i++)
		if (sops[i].sem_num < 0 ||
				sops[i].sem_num >= sem->semid_ds.sem_nsems)
			goto out_free;

	/* check for duplicate number */
	r = EINVAL;
	for (i = 0; i < nsops; i++)
		for (j = i + 1; j < nsops; j++)
			if (sops[i].sem_num == sops[j].sem_num)
				goto out_free;

	/* check for EAGAIN error */
	r = EAGAIN;
	for (i = 0; i < nsops; i++) {
		int op_n, val;

		op_n = sops[i].sem_op;
		val = sem->sems[sops[i].sem_num].semval;

		if ((sops[i].sem_flg & IPC_NOWAIT) &&
				((!op_n && val) ||
				 (op_n < 0 &&
				  -op_n > val)))
			goto out_free;

	}
	/* there will be no errors left, so we can go ahead */
	for (i = 0; i < nsops; i++) {
		struct semaphore *s;
		int op_n;

		s = &sem->sems[sops[i].sem_num];
		op_n = sops[i].sem_op;

		s->sempid = getnpid(who_e);

		if (op_n > 0) {
			/* check for alter permission */
			r = EACCES;
			if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
				goto out_free;
			s->semval += sops[i].sem_op;
		} else if (!op_n) {
			if (s->semval) {
				/* put the process asleep */
				s->semzcnt++;
				s->zlist = realloc(s->zlist, sizeof(struct waiting) * s->semzcnt);
				if (!s->zlist) {
					printf("IPC: zero waiting list lost...\n");
					break;
				}
				s->zlist[s->semzcnt-1].who = who_e;
				s->zlist[s->semzcnt-1].val = op_n;

#ifdef DEBUG_SEM
				printf("SEMOP: Put into sleep... %d\n", who_e);
#endif
				no_reply++;
			}
		} else {
			/* check for alter permission */
			r = EACCES;
			if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
				goto out_free;
			if (s->semval >= -op_n)
				s->semval += op_n;
			else {
				/* put the process asleep */
				s->semncnt++;
				s->nlist = realloc(s->nlist, sizeof(struct waiting) * s->semncnt);
				if (!s->nlist) {
					printf("IPC: increase waiting list lost...\n");
					break;
				}
				s->nlist[s->semncnt-1].who = who_e;
				s->nlist[s->semncnt-1].val = -op_n;

				no_reply++;
			}
		}
	}

	r = OK;
out_free:
	free(sops);
out:
	/* if we reach here by errors
	 * or with no errors but we should reply back.
	 */
	if (r != OK || !no_reply) {
		m->m_type = r;

		sendnb(who_e, m);
	}

	/* awaken process if possible */
	update_semaphores();

	return 0;
}