Beispiel #1
0
static int
set_rctl(char *rctl, uint64_t value, rctl_priv_t priv)
{
	rctlblk_t *oblk, *nblk;
	boolean_t priv_deny = B_FALSE;
	int priv_sig = 0;

	if (value == LX_RLIM64_INFINITY)
		value = get_rctl_max(rctl);

	/*
	 * The brand library cannot use malloc(3C) so we allocate the space
	 * with SAFE_ALLOCA(). Thus there's no need to free it when we're done.
	 */
	oblk = (rctlblk_t *)SAFE_ALLOCA(rctlblk_size());
	nblk = (rctlblk_t *)SAFE_ALLOCA(rctlblk_size());

	if (getrctl(rctl, NULL, oblk, RCTL_FIRST) == -1)
		return (-errno);

	do {
		if (rctlblk_get_privilege(oblk) == RCPRIV_PRIVILEGED &&
		    rctlblk_get_local_action(oblk, &priv_sig) & RCTL_LOCAL_DENY)
			priv_deny = B_TRUE;

		if (rctlblk_get_privilege(oblk) != priv)
			continue;

		/* we're already at this value, nothing to do */
		if (rctlblk_get_value(oblk) == value)
			return (0);

		/* non-root cannot raise privileged limit */
		if (priv == RCPRIV_PRIVILEGED && geteuid() != 0 &&
		    value > rctlblk_get_value(oblk))
			return (-EPERM);

		bcopy(oblk, nblk, rctlblk_size());
		rctlblk_set_value(nblk, value);
		if (setrctl(rctl, oblk, nblk, RCTL_REPLACE) == -1)
			return (-errno);
		return (0);
	} while (getrctl(rctl, oblk, oblk, RCTL_NEXT) != -1);

	/* not there, add it */
	bzero(nblk, rctlblk_size());
	rctlblk_set_value(nblk, value);
	rctlblk_set_privilege(nblk, priv);
	if (priv_deny) {
		rctlblk_set_local_action(nblk, RCTL_LOCAL_DENY, 0);
	} else {
		rctlblk_set_local_action(nblk, RCTL_LOCAL_SIGNAL, priv_sig);
	}

	if (setrctl(rctl, NULL, nblk, RCTL_INSERT) == -1)
		return (-errno);

	return (0);
}
Beispiel #2
0
static int
lx_getpeername(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct sockaddr *name;
	socklen_t namelen;

	if (uucopy((void *)args[2], &namelen, sizeof (socklen_t)) != 0)
		return (-errno);

	lx_debug("\tgetpeername(%d, 0x%p, 0x%p (=%d))",
	    sockfd, args[1], args[2], namelen);

	/*
	 * Linux returns EFAULT in this case, even if the namelen parameter
	 * is 0.  This check will not catch other illegal addresses, but
	 * the benefit catching a non-null illegal address here is not
	 * worth the cost of another system call.
	 */
	if ((void *)args[1] == NULL)
		return (-EFAULT);

	if ((name = SAFE_ALLOCA(namelen)) == NULL)
		return (-EINVAL);
	if ((getpeername(sockfd, name, &namelen)) < 0)
		return (-errno);

	if (uucopy(name, (void *)args[1], namelen) != 0)
		return (-errno);

	if (uucopy(&namelen, (void *)args[2], sizeof (socklen_t)) != 0)
		return (-errno);

	return (0);
}
Beispiel #3
0
static void
au_play (struct sound *s, struct sound_device *sd)
{
  struct au_header *header = (struct au_header *) s->header;

  sd->sample_size = 0;
  sd->sample_rate = header->sample_rate;
  sd->bps = 0;
  sd->channels = header->channels;
  sd->choose_format (sd, s);
  sd->configure (sd);

  if (STRINGP (s->data))
    sd->write (sd, SSDATA (s->data) + header->data_offset,
	       SBYTES (s->data) - header->data_offset);
  else
    {
      ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
      ptrdiff_t nbytes;

      /* Seek */
      lseek (s->fd, header->data_offset, SEEK_SET);

      /* Copy sound data to the device.  */
      USE_SAFE_ALLOCA;
      char *buffer = SAFE_ALLOCA (blksize);
      while ((nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
	sd->write (sd, buffer, nbytes);

      if (nbytes < 0)
	sound_perror ("Error reading sound file");
      SAFE_FREE ();
    }
}
Beispiel #4
0
/*
 * For the SETALL operation, we have to examine each of the semaphore
 * values to be sure it is legal.
 */
static int
lx_semctl_setall(int semid, ushort_t *arg)
{
	struct semid_ds semds;
	ushort_t *vals;
	int i, sz, r;

	/*
	 * Find out how many semaphores are involved, reserve enough
	 * memory for an internal copy of the array, and then copy it in
	 * from the process.
	 */
	if (semctl(semid, 0, IPC_STAT, &semds) != 0)
		return (-errno);
	sz = semds.sem_nsems * sizeof (ushort_t);
	if ((vals = SAFE_ALLOCA(sz)) == NULL)
		return (-ENOMEM);
	if (uucopy(arg, vals, sz))
		return (-errno);

	/* Validate each of the values. */
	for (i = 0; i < semds.sem_nsems; i++)
		if (vals[i] > LX_SEMVMX)
			return (-ERANGE);

	r = semctl(semid, 0, SETALL, arg);

	return ((r < 0) ? -errno : r);
}
Beispiel #5
0
/*
 * Given a slot number and a maximum number of ids to extract from the
 * kernel, return the msgid in the provided slot.
 */
static int
slot_to_id(int type, int slot)
{
	uint_t nids, max;
	int *idbuf = NULL;
	int r = 0;

	nids = 0;
	for (;;) {
		switch (type) {
		case SLOT_SEM:
			r = semids(idbuf, nids, &max);
			break;
		case SLOT_SHM:
			r = shmids(idbuf, nids, &max);
			break;
		case SLOT_MSG:
			r = msgids(idbuf, nids, &max);
			break;
		}

		if (r < 0)
			return (-errno);

		if (max == 0)
			return (-EINVAL);

		if (max <= nids)
			return (idbuf[slot]);

		nids = max;
		if ((idbuf = (int *)SAFE_ALLOCA(sizeof (int) * nids)) == NULL)
			return (-ENOMEM);
	}
}
Beispiel #6
0
static int
lx_connect(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct sockaddr *name;
	socklen_t len;
	int r;
	int nlen;
	lx_addr_type_t type;

	if ((nlen = calc_addr_size((struct sockaddr *)args[1], (int)args[2],
	    &type)) < 0)
		return (nlen);

	if ((name = SAFE_ALLOCA(nlen)) == NULL)
		return (-EINVAL);

	if ((r = convert_sockaddr(name, &len, (struct sockaddr *)args[1],
	    (socklen_t)args[2])) < 0)
		return (r);

	lx_debug("\tconnect(%d, 0x%p, %d)", sockfd, name, len);

	if (name->sa_family == AF_UNIX)
		lx_debug("\t\tAF_UNIX, path = %s", name->sa_data);

	r = connect(sockfd, name, len);

	return ((r < 0) ? -errno : r);
}
Beispiel #7
0
static int
lock_file_1 (char *lfname, int force)
{
  int err;
  int symlink_errno;
  USE_SAFE_ALLOCA;

  /* Call this first because it can GC.  */
  printmax_t boot = get_boot_time ();

  Lisp_Object luser_name = Fuser_login_name (Qnil);
  char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : "";
  Lisp_Object lhost_name = Fsystem_name ();
  char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : "";
  ptrdiff_t lock_info_size = (strlen (user_name) + strlen (host_name)
			      + 2 * INT_STRLEN_BOUND (printmax_t)
			      + sizeof "@.:");
  char *lock_info_str = SAFE_ALLOCA (lock_info_size);
  printmax_t pid = getpid ();

  esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd,
	    user_name, host_name, pid, boot);

  err = symlink (lock_info_str, lfname);
  if (errno == EEXIST && force)
    {
      unlink (lfname);
      err = symlink (lock_info_str, lfname);
    }

  symlink_errno = errno;
  SAFE_FREE ();
  errno = symlink_errno;
  return err == 0;
}
Beispiel #8
0
/* ARGSUSED */
long
lx_sched_getaffinity(uintptr_t pid, uintptr_t len, uintptr_t maskp)
{
	int	sz;
	ulong_t	*lmask, *zmask;
	int	i;

	sz = syscall(SYS_brand, B_GET_AFFINITY_MASK, pid, len, maskp);
	if (sz == -1)
		return (-errno);

	/*
	 * If the target LWP hasn't ever had an affinity mask set, the kernel
	 * will return a mask of all 0's. If that is the case we must build a
	 * default mask that has all valid bits turned on.
	 */
	lmask = SAFE_ALLOCA(sz);
	zmask = SAFE_ALLOCA(sz);
	if (lmask == NULL || zmask == NULL)
		return (-ENOMEM);

	bzero(zmask, sz);

	if (uucopy((void *)maskp, lmask, sz) != 0)
		return (-EFAULT);

	if (bcmp(lmask, zmask, sz) != 0)
		return (sz);

	for (i = 0; i < sz * 8; i++) {
		if (p_online(i, P_STATUS) != -1) {
			lmask[BITINDEX(i)] |= BITSHIFT(i);
		}
	}

	if (uucopy(lmask, (void *)maskp, sz) != 0)
		return (-EFAULT);

	return (sz);
}
Beispiel #9
0
static int
lx_semctl_ipcinfo(void *buf)
{
	struct lx_seminfo i;
	rctlblk_t *rblk;
	int rblksz;
	uint_t nids;
	int idbuf;
	int err;
	uint64_t val;

	rblksz = rctlblk_size();
	if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
		return (-ENOMEM);

	bzero(&i, sizeof (i));
	err = get_rctlval(rblk, "project.max-sem-ids", (ulong_t)MAXINT, &val);
	if (err < 0)
		return (err);
	i.semmni = (int)val;
	err = get_rctlval(rblk, "process.max-sem-nsems", (ulong_t)MAXINT, &val);
	if (err < 0)
		return (err);
	i.semmsl = (int)val;
	err = get_rctlval(rblk, "process.max-sem-ops", (ulong_t)MAXINT, &val);
	if (err < 0)
		return (err);
	i.semopm = (int)val;

	/*
	 * We don't have corresponding rctls for these fields.  The values
	 * are taken from the formulas used to derive the defaults listed
	 * in the Linux header file.  We're lying, but trying to be
	 * coherent about it.
	 */
	i.semmap = i.semmni;
	i.semmns = i.semmni * i.semmsl;
	i.semmnu = INT_MAX;
	i.semume = INT_MAX;
	i.semvmx = LX_SEMVMX;
	if (semids(&idbuf, 0, &nids) < 0)
		return (-errno);
	i.semusz = nids;
	i.semaem = INT_MAX;

	if (uucopy(&i, buf, sizeof (i)) != 0)
		return (-errno);

	return (nids);
}
Beispiel #10
0
static void
wav_play (struct sound *s, struct sound_device *sd)
{
  struct wav_header *header = (struct wav_header *) s->header;

  /* Let the device choose a suitable device-dependent format
     for the file.  */
  sd->choose_format (sd, s);

  /* Configure the device.  */
  sd->sample_size = header->sample_size;
  sd->sample_rate = header->sample_rate;
  sd->bps = header->bytes_per_second;
  sd->channels = header->channels;
  sd->configure (sd);

  /* Copy sound data to the device.  The WAV file specification is
     actually more complex.  This simple scheme worked with all WAV
     files I found so far.  If someone feels inclined to implement the
     whole RIFF-WAVE spec, please do.  */
  if (STRINGP (s->data))
    sd->write (sd, SSDATA (s->data) + sizeof *header,
	       SBYTES (s->data) - sizeof *header);
  else
    {
      ptrdiff_t nbytes = 0;
      ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
      ptrdiff_t data_left = header->data_length;
      USE_SAFE_ALLOCA;
      char *buffer = SAFE_ALLOCA (blksize);
      lseek (s->fd, sizeof *header, SEEK_SET);
      while (data_left > 0
             && (nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
        {
          /* Don't play possible garbage at the end of file */
          if (data_left < nbytes) nbytes = data_left;
          data_left -= nbytes;
          sd->write (sd, buffer, nbytes);
        }

      if (nbytes < 0)
	sound_perror ("Error reading sound file");
      SAFE_FREE ();
    }
}
Beispiel #11
0
/*
 * Check to see if we have the permissions to set scheduler parameters and
 * policy, based on Linux' demand that such commands fail with errno set to
 * EPERM if the current euid is not the euid or ruid of the process in
 * question.
 */
static int
check_schedperms(pid_t pid)
{
	size_t sz;
	ucred_t *cr;
	uid_t euid;

	euid = geteuid();

	if (pid == getpid()) {
		/*
		 * If we're the process to be checked, simply check the euid
		 * against our ruid.
		 */
		if (euid != getuid())
			return (-EPERM);

		return (0);
	}

	/*
	 * We allocate a ucred_t ourselves rather than call ucred_get(3C)
	 * because ucred_get() calls malloc(3C), which the brand library cannot
	 * use.  Because we allocate the space with SAFE_ALLOCA(), there's
	 * no need to free it when we're done.
	 */
	sz = ucred_size();
	cr = (ucred_t *)SAFE_ALLOCA(sz);

	if (cr == NULL)
		return (-ENOMEM);

	/*
	 * If we can't access the process' credentials, fail with errno EPERM
	 * as the call would not have succeeded anyway.
	 */
	if (syscall(SYS_ucredsys, UCREDSYS_UCREDGET, pid, cr) != 0)
		return ((errno == EACCES) ? -EPERM : -errno);

	if ((euid != ucred_geteuid(cr)) && (euid != ucred_getruid(cr)))
		return (-EPERM);

	return (0);
}
Beispiel #12
0
/* This callback is called when the FD is available for read.  The inotify
   events are read from FD and converted into input_events.  */
static void
inotify_callback (int fd, void *_)
{
  int to_read;
  if (ioctl (fd, FIONREAD, &to_read) < 0)
    report_file_notify_error ("Error while retrieving file system events",
			      Qnil);
  USE_SAFE_ALLOCA;
  char *buffer = SAFE_ALLOCA (to_read);
  ssize_t n = read (fd, buffer, to_read);
  if (n < 0)
    report_file_notify_error ("Error while reading file system events", Qnil);

  struct input_event event;
  EVENT_INIT (event);
  event.kind = FILE_NOTIFY_EVENT;

  for (ssize_t i = 0; i < n; )
    {
      struct inotify_event *ev = (struct inotify_event *) &buffer[i];
      Lisp_Object descriptor = INTEGER_TO_CONS (ev->wd);
      Lisp_Object prevtail = find_descriptor (descriptor);

      if (! NILP (prevtail))
        {
	  Lisp_Object tail = CONSP (prevtail) ? XCDR (prevtail) : watch_list;
	  for (Lisp_Object watches = XCDR (XCAR (tail)); ! NILP (watches);
	       watches = XCDR (watches))
            {
              event.arg = inotifyevent_to_event (XCAR (watches), ev);
              if (!NILP (event.arg))
                kbd_buffer_store_event (&event);
            }
          /* If event was removed automatically: Drop it from watch list.  */
          if (ev->mask & IN_IGNORED)
	    remove_descriptor (prevtail, true);
        }
      i += sizeof (*ev) + ev->len;
    }

  SAFE_FREE ();
}
Beispiel #13
0
static int
lx_shmctl_ipcinfo(void *buf)
{
	struct lx_shminfo s;
	rctlblk_t *rblk;
	int rblksz;
	int err;
	uint64_t val;

	rblksz = rctlblk_size();
	if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
		return (-ENOMEM);

	bzero(&s, sizeof (s));
	err = get_rctlval(rblk, "project.max-shm-ids", ULONG_MAX, &val);
	if (err < 0)
		return (err);
	s.shmmni = val;
	err = get_rctlval(rblk, "project.max-shm-memory", ULONG_MAX, &val);
	if (err < 0)
		return (err);
	s.shmmax = val;

	/*
	 * We don't have corresponding rctls for these fields.  The values
	 * are taken from the formulas used to derive the defaults listed
	 * in the Linux header file.  We're lying, but trying to be
	 * coherent about it.
	 */
	s.shmmin = 1;
	s.shmseg = ULONG_MAX;
	s.shmall = s.shmmax / getpagesize();

	if (uucopy(&s, buf, sizeof (s)))
		return (-errno);

	return (0);
}
Beispiel #14
0
static uint64_t
get_rctl_max(char *rctl)
{
	rctlblk_t *rblk;
	uint64_t inf;

	/*
	 * The brand library cannot use malloc(3C) so we allocate the space
	 * with SAFE_ALLOCA(). Thus there's no need to free it when we're done.
	 */
	rblk = (rctlblk_t *)SAFE_ALLOCA(rctlblk_size());

	if (getrctl(rctl, NULL, rblk, RCTL_FIRST) == -1)
		return (-errno);

	do {
		switch (rctlblk_get_privilege(rblk)) {
		case RCPRIV_BASIC:
		case RCPRIV_PRIVILEGED:
			inf = rctlblk_get_value(rblk);
			if (rctlblk_get_local_flags(rblk) &
			    RCTL_LOCAL_MAXIMAL &&
			    rctlblk_get_global_flags(rblk) &
			    RCTL_GLOBAL_INFINITE)
				return (inf);
			break;

		case RCPRIV_SYSTEM:
			inf = rctlblk_get_value(rblk);
			return (inf);
			break;
		}
	} while (getrctl(rctl, rblk, rblk, RCTL_NEXT) != -1);

	/* Somehow we have no max, use the Linux infinite value */
	return (LX_RLIM64_INFINITY);
}
Beispiel #15
0
static int
lx_getsockname(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct sockaddr *name = NULL;
	socklen_t namelen, namelen_orig;

	if (uucopy((void *)args[2], &namelen, sizeof (socklen_t)) != 0)
		return (-errno);
	namelen_orig = namelen;

	lx_debug("\tgetsockname(%d, 0x%p, 0x%p (=%d))",
	    sockfd, args[1], args[2], namelen);

	if (namelen > 0) {
		if ((name = SAFE_ALLOCA(namelen)) == NULL)
			return (-EINVAL);
		bzero(name, namelen);
	}

	if (getsockname(sockfd, name, &namelen) < 0)
		return (-errno);

	/*
	 * If the name that getsockname() wants to return is larger
	 * than namelen, getsockname() will copy out the maximum amount
	 * of data possible and then update namelen to indicate the
	 * actually size of all the data that it wanted to copy out.
	 */
	if (uucopy(name, (void *)args[1], namelen_orig) != 0)
		return (-errno);
	if (uucopy(&namelen, (void *)args[2], sizeof (socklen_t)) != 0)
		return (-errno);

	return (0);
}
Beispiel #16
0
static void
do_scrolling (struct frame *frame, struct glyph_matrix *current_matrix,
              struct matrix_elt *matrix, int window_size,
              int unchanged_at_top)
{
  struct matrix_elt *p;
  int i, j, k;
  USE_SAFE_ALLOCA;

  /* True if we have set a terminal window with set_terminal_window.  */
  bool terminal_window_p = 0;

  /* A queue for line insertions to be done.  */
  struct queue { int count, pos; };
  struct queue *queue_start;
  SAFE_NALLOCA (queue_start, 1, current_matrix->nrows);
  struct queue *queue = queue_start;

  char *retained_p = SAFE_ALLOCA (window_size);
  int *copy_from;
  SAFE_NALLOCA (copy_from, 1, window_size);

  /* Zero means line is empty.  */
  memset (retained_p, 0, window_size * sizeof (char));
  for (k = 0; k < window_size; ++k)
    copy_from[k] = -1;

#ifdef GLYPH_DEBUG
# define CHECK_BOUNDS							\
  do									\
    {									\
      int ck;								\
      for (ck = 0; ck < window_size; ++ck)				\
	eassert (copy_from[ck] == -1					\
		 || (copy_from[ck] >= 0 && copy_from[ck] < window_size)); \
    }									\
  while (0);
#endif

  /* When j is advanced, this corresponds to deleted lines.
     When i is advanced, this corresponds to inserted lines.  */
  i = j = window_size;
  while (i > 0 || j > 0)
    {
      p = matrix + i * (window_size + 1) + j;

      if (p->insertcost < p->writecost && p->insertcost < p->deletecost)
	{
	  /* Insert should be done at vpos i-1, plus maybe some before.
	     Queue the screen operation to be performed.  */
	  queue->count = p->insertcount;
	  queue->pos = i + unchanged_at_top - p->insertcount;
	  ++queue;

	  /* By incrementing I, we leave room in the result rows
	     for the empty rows opened up.  */
	  i -= p->insertcount;
	}
      else if (p->deletecost < p->writecost)
	{
	  /* Old line at vpos j-1, and maybe some before it, should be
	     deleted.  By decrementing J, we skip some lines in the
	     temp_rows which is equivalent to omitting these lines in
	     the result rows, thus deleting them.  */
	  j -= p->deletecount;

	  /* Set the terminal window, if not done already.  */
 	  if (! terminal_window_p)
	    {
	      set_terminal_window (frame, window_size + unchanged_at_top);
	      terminal_window_p = 1;
	    }

	  /* Delete lines on the terminal.  */
	  ins_del_lines (frame, j + unchanged_at_top, - p->deletecount);
	}
      else
	{
	  /* Best thing done here is no insert or delete, i.e. a write.  */
	  --i, --j;
	  eassert (i >= 0 && i < window_size);
	  eassert (j >= 0 && j < window_size);
	  copy_from[i] = j;
	  retained_p[j] = 1;

#ifdef GLYPH_DEBUG
	  CHECK_BOUNDS;
#endif
	}
    }

  /* Now do all insertions queued above.  */
  if (queue > queue_start)
    {
      int next = -1;

      /* Set the terminal window if not yet done.  */
      if (!terminal_window_p)
	{
	  set_terminal_window (frame, window_size + unchanged_at_top);
	  terminal_window_p = 1;
	}

      do
	{
	  --queue;

	  /* Do the deletion on the terminal.  */
	  ins_del_lines (frame, queue->pos, queue->count);

	  /* All lines in the range deleted become empty in the glyph
	     matrix.  Assign to them glyph rows that are not retained.
	     K is the starting position of the deleted range relative
	     to the window we are working in.  */
	  k = queue->pos - unchanged_at_top;
	  for (j = 0; j < queue->count; ++j)
	    {
	      /* Find the next row not retained.  */
	      while (retained_p[++next])
		;

	      /* Record that this row is to be used for the empty
		 glyph row j.  */
	      copy_from[k + j] = next;
	    }
	}
      while (queue > queue_start);

    }

  for (k = 0; k < window_size; ++k)
    eassert (copy_from[k] >= 0 && copy_from[k] < window_size);

  /* Perform the row swizzling.  */
  mirrored_line_dance (current_matrix, unchanged_at_top, window_size,
		       copy_from, retained_p);

  /* Some sanity checks if GLYPH_DEBUG is defined.  */
  CHECK_MATRIX (current_matrix);

  if (terminal_window_p)
    set_terminal_window (frame, 0);
  SAFE_FREE ();
}
Beispiel #17
0
Lisp_Object
get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
{
  char *from, *to, *name, *p, *p1;
  int fd;
  ptrdiff_t minsize;
  int offset;
  EMACS_INT position;
  Lisp_Object file, tem;
  USE_SAFE_ALLOCA;

  if (INTEGERP (filepos))
    {
      file = Vdoc_file_name;
      position = XINT (filepos);
    }
  else if (CONSP (filepos))
    {
      file = XCAR (filepos);
      position = XINT (XCDR (filepos));
    }
  else
    return Qnil;

  if (position < 0)
    position = - position;

  if (!STRINGP (Vdoc_directory))
    return Qnil;

  if (!STRINGP (file))
    return Qnil;

  /* Put the file name in NAME as a C string.
     If it is relative, combine it with Vdoc_directory.  */

  tem = Ffile_name_absolute_p (file);
  file = ENCODE_FILE (file);
  if (NILP (tem))
    {
      Lisp_Object docdir = ENCODE_FILE (Vdoc_directory);
      minsize = SCHARS (docdir);
      /* sizeof ("../etc/") == 8 */
      if (minsize < 8)
	minsize = 8;
      name = SAFE_ALLOCA (minsize + SCHARS (file) + 8);
      strcpy (name, SSDATA (docdir));
      strcat (name, SSDATA (file));
    }
  else
    {
      name = SSDATA (file);
    }

  fd = emacs_open (name, O_RDONLY, 0);
  if (fd < 0)
    {
#ifndef CANNOT_DUMP
      if (!NILP (Vpurify_flag))
	{
	  /* Preparing to dump; DOC file is probably not installed.
	     So check in ../etc.  */
	  strcpy (name, "../etc/");
	  strcat (name, SSDATA (file));

	  fd = emacs_open (name, O_RDONLY, 0);
	}
#endif
      if (fd < 0)
	error ("Cannot open doc string file \"%s\"", name);
    }

  /* Seek only to beginning of disk block.  */
  /* Make sure we read at least 1024 bytes before `position'
     so we can check the leading text for consistency.  */
  offset = min (position, max (1024, position % (8 * 1024)));
  if (TYPE_MAXIMUM (off_t) < position
      || lseek (fd, position - offset, 0) < 0)
    {
      emacs_close (fd);
      error ("Position %"pI"d out of range in doc string file \"%s\"",
	     position, name);
    }

  SAFE_FREE ();

  /* Read the doc string into get_doc_string_buffer.
     P points beyond the data just read.  */

  p = get_doc_string_buffer;
  while (1)
    {
      ptrdiff_t space_left = (get_doc_string_buffer_size - 1
			      - (p - get_doc_string_buffer));
      int nread;

      /* Allocate or grow the buffer if we need to.  */
      if (space_left <= 0)
	{
	  ptrdiff_t in_buffer = p - get_doc_string_buffer;
	  get_doc_string_buffer =
	    xpalloc (get_doc_string_buffer, &get_doc_string_buffer_size,
		     16 * 1024, -1, 1);
	  p = get_doc_string_buffer + in_buffer;
	  space_left = (get_doc_string_buffer_size - 1
			- (p - get_doc_string_buffer));
	}

      /* Read a disk block at a time.
         If we read the same block last time, maybe skip this?  */
      if (space_left > 1024 * 8)
	space_left = 1024 * 8;
      nread = emacs_read (fd, p, space_left);
      if (nread < 0)
	{
	  emacs_close (fd);
	  error ("Read error on documentation file");
	}
      p[nread] = 0;
      if (!nread)
	break;
      if (p == get_doc_string_buffer)
	p1 = strchr (p + offset, '\037');
      else
	p1 = strchr (p, '\037');
      if (p1)
	{
	  *p1 = 0;
	  p = p1;
	  break;
	}
      p += nread;
    }
  emacs_close (fd);

  /* Sanity checking.  */
  if (CONSP (filepos))
    {
      int test = 1;
      if (get_doc_string_buffer[offset - test++] != ' ')
	return Qnil;
      while (get_doc_string_buffer[offset - test] >= '0'
	     && get_doc_string_buffer[offset - test] <= '9')
	test++;
      if (get_doc_string_buffer[offset - test++] != '@'
	  || get_doc_string_buffer[offset - test] != '#')
	return Qnil;
    }
  else
    {
      int test = 1;
      if (get_doc_string_buffer[offset - test++] != '\n')
	return Qnil;
      while (get_doc_string_buffer[offset - test] > ' ')
	test++;
      if (get_doc_string_buffer[offset - test] != '\037')
	return Qnil;
    }

  /* Scan the text and perform quoting with ^A (char code 1).
     ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_.  */
  from = get_doc_string_buffer + offset;
  to = get_doc_string_buffer + offset;
  while (from != p)
    {
      if (*from == 1)
	{
	  int c;

	  from++;
	  c = *from++;
	  if (c == 1)
	    *to++ = c;
	  else if (c == '0')
	    *to++ = 0;
	  else if (c == '_')
	    *to++ = 037;
	  else
	    {
	      unsigned char uc = c;
	      error ("\
Invalid data in documentation file -- %c followed by code %03o",
		     1, uc);
	    }
	}
      else
	*to++ = *from++;
    }

  /* If DEFINITION, read from this buffer
     the same way we would read bytes from a file.  */
  if (definition)
    {
      read_bytecode_pointer = (unsigned char *) get_doc_string_buffer + offset;
      return Fread (Qlambda);
    }

  if (unibyte)
    return make_unibyte_string (get_doc_string_buffer + offset,
				to - (get_doc_string_buffer + offset));
  else
    {
      /* The data determines whether the string is multibyte.  */
      ptrdiff_t nchars =
	multibyte_chars_in_text (((unsigned char *) get_doc_string_buffer
				  + offset),
				 to - (get_doc_string_buffer + offset));
      return make_string_from_bytes (get_doc_string_buffer + offset,
				     nchars,
				     to - (get_doc_string_buffer + offset));
    }
}
Beispiel #18
0
static int
lx_msgctl_ipcinfo(int cmd, void *buf)
{
	struct lx_msginfo m;
	rctlblk_t *rblk;
	int idbuf, rblksz, msgseg, maxmsgs;
	uint_t nids;
	int rval;
	int err;
	uint64_t val;

	rblksz = rctlblk_size();
	if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
		return (-ENOMEM);

	bzero(&m, sizeof (m));
	err = get_rctlval(rblk, "project.max-msg-ids", (ulong_t)MAXINT, &val);
	if (err < 0)
		return (err);
	m.msgmni = (int)val;
	err = get_rctlval(rblk, "process.max-msg-qbytes", (ulong_t)MAXINT,
	    &val);
	if (err < 0)
		return (err);
	m.msgmnb = (int)val;

	if (cmd == LX_IPC_INFO) {
		err = get_rctlval(rblk, "process.max-msg-messages",
		    (ulong_t)MAXINT, &val);
		if (err < 0)
			return (err);
		maxmsgs = (int)val;
		m.msgtql = maxmsgs * m.msgmni;
		m.msgmap = m.msgmnb;
		m.msgpool = m.msgmax * m.msgmnb;
		rval = 0;
	} else {
		if (msgids(&idbuf, 0, &nids) < 0)
			return (-errno);
		m.msgpool = nids;

		/*
		 * For these fields, we can't even come up with a good fake
		 * approximation.  These are listed as 'obsolete' or
		 * 'unused' in the header files, so hopefully nobody is
		 * relying on them anyway.
		 */
		m.msgtql = INT_MAX;
		m.msgmap = INT_MAX;
		rval = nids;
	}

	/*
	 * We don't have corresponding rctls for these fields.  The values
	 * are taken from the formulas used to derive the defaults listed
	 * in the Linux header file.  We're lying, but trying to be
	 * coherent about it.
	 */
	m.msgmax = m.msgmnb;
	m.msgssz = 16;
	msgseg = (m.msgpool * 1024) / m.msgssz;
	m.msgseg = (msgseg > 0xffff) ? 0xffff : msgseg;

	if (uucopy(&m, buf, sizeof (m)))
		return (-errno);
	return (rval);
}
Beispiel #19
0
static int
lx_getsockopt(ulong_t *args)
{
	int sockfd = (int)args[0];
	int level = (int)args[1];
	int optname = (int)args[2];
	void *optval = (void *)args[3];
	int *optlenp = (int *)args[4];
	int r;
	int orig_optname;
	lx_proto_opts_t *proto_opts;

	lx_debug("\tgetsockopt(%d, %d, %d, 0x%p, 0x%p)", sockfd, level, optname,
	    optval, optlenp);

	/*
	 * According to the Linux man page, a NULL optval should indicate
	 * (as in Solaris) that no return value is expected.  Instead, it
	 * actually triggers an EFAULT error.
	 */
	if (optval == NULL)
		return (-EFAULT);

	if (level > LX_IPPROTO_RAW || level == LX_IPPROTO_UDP)
		return (-EOPNOTSUPP);

	if ((proto_opts = get_proto_opt_tbl(level)) == NULL)
		return (-ENOPROTOOPT);

	if (optname <= 0 || optname >= (proto_opts->maxentries)) {
		lx_unsupported("Unsupported sockopt %d, proto %d", optname,
		    level);
		return (-ENOPROTOOPT);
	}

	if ((level == LX_IPPROTO_TCP) && (optname == LX_TCP_CORK)) {
		/*
		 * We don't support TCP_CORK but some apps rely on it.  So,
		 * rather than return an error we just return 0.  This
		 * isn't exactly a lie, since this option really isn't set,
		 * but it's not the whole truth either.  Fortunately, we
		 * aren't under oath.
		 */
		r = 0;
		if (uucopy(&r, optval, sizeof (int)) != 0)
			return (-errno);
		r = sizeof (int);
		if (uucopy(&r, optlenp, sizeof (int)) != 0)
			return (-errno);
		return (0);
	}
	if ((level == LX_SOL_SOCKET) && (optname == LX_SO_PEERCRED)) {
		struct lx_ucred	lx_ucred;
		ucred_t		*ucp;

		/*
		 * We don't support SO_PEERCRED, but we do have equivalent
		 * functionality in getpeerucred() so invoke that here.
		 */

		/* Verify there's going to be enough room for the results. */
		if (uucopy(optlenp, &r, sizeof (int)) != 0)
			return (-errno);
		if (r < sizeof (struct lx_ucred))
			return (-EOVERFLOW);

		/*
		 * We allocate a ucred_t ourselves rather than allow
		 * getpeerucred() to do it for us because getpeerucred()
		 * uses malloc(3C) and we'd rather use SAFE_ALLOCA().
		 */
		if ((ucp = (ucred_t *)SAFE_ALLOCA(ucred_size())) == NULL)
			return (-ENOMEM);

		/* Get the credential for the remote end of this socket. */
		if (getpeerucred(sockfd, &ucp) != 0)
			return (-errno);
		if (((lx_ucred.lxu_pid = ucred_getpid(ucp)) == -1) ||
		    ((lx_ucred.lxu_uid = ucred_geteuid(ucp)) == (uid_t)-1) ||
		    ((lx_ucred.lxu_gid = ucred_getegid(ucp)) == (gid_t)-1)) {
			return (-errno);
		}

		/* Copy out the results. */
		if ((uucopy(&lx_ucred, optval, sizeof (lx_ucred))) != 0)
			return (-errno);
		r = sizeof (lx_ucred);
		if ((uucopy(&r, optlenp, sizeof (int))) != 0)
			return (-errno);
		return (0);
	}

	orig_optname = optname;

	optname = proto_opts->proto[optname];
	if (optname == OPTNOTSUP) {
		lx_unsupported("unsupported sockopt %d, proto %d",
		    orig_optname, level);
		return (-ENOPROTOOPT);
	}

	if (level == LX_SOL_SOCKET)
		level = SOL_SOCKET;

	r = getsockopt(sockfd, level, optname, optval, optlenp);

	if (r == 0 && level == SOL_SOCKET && optname == SO_TYPE) {
		/* translate our type back to Linux */
		*(int *)optval = stol_socktype[(*(int *)optval)];
	}

	return ((r < 0) ? -errno : r);
}
Beispiel #20
0
static ssize_t
lx_sendto(ulong_t *args)
{
	int sockfd = (int)args[0];
	void *buf = (void *)args[1];
	size_t len = (size_t)args[2];
	int flags = (int)args[3];
	struct sockaddr *to = NULL;
	socklen_t tolen = 0;
	ssize_t r;
	int nlen;
	lx_addr_type_t type;

	int nosigpipe = flags & LX_MSG_NOSIGNAL;
	struct sigaction newact, oact;

	if ((args[4] != NULL) && (args[5] > 0)) {
		if ((nlen = calc_addr_size((struct sockaddr *)args[4],
		    (int)args[5], &type)) < 0)
			return (nlen);

		if ((to = SAFE_ALLOCA(nlen)) == NULL)
			return (-EINVAL);

		if ((r = convert_sockaddr(to, &tolen,
		    (struct sockaddr *)args[4], (socklen_t)args[5])) < 0)
			return (r);
	}


	lx_debug("\tsendto(%d, 0x%p, 0x%d, 0x%x, 0x%x, %d)", sockfd, buf, len,
	    flags, to, tolen);

	flags = convert_sockflags(flags);

	/*
	 * Return this error if we try to write to our emulated netlink
	 * socket. This makes the auditing subsystem happy.
	 */
	if (to && type == lxa_netlink) {
		return (-ECONNREFUSED);
	}

	/*
	 * If nosigpipe is set, we want to emulate the Linux action of
	 * not sending a SIGPIPE to the caller if the remote socket has
	 * already been closed.
	 *
	 * As SIGPIPE is a directed signal sent only to the thread that
	 * performed the action, we can emulate this behavior by momentarily
	 * resetting the action for SIGPIPE to SIG_IGN, performing the socket
	 * call, and resetting the action back to its previous value.
	 */
	if (nosigpipe) {
		newact.sa_handler = SIG_IGN;
		newact.sa_flags = 0;
		(void) sigemptyset(&newact.sa_mask);

		if (sigaction(SIGPIPE, &newact, &oact) < 0)
			lx_err_fatal(gettext(
			    "%s: could not ignore SIGPIPE to emulate "
			    "LX_MSG_NOSIGNAL"), "sendto()");
	}

	r = sendto(sockfd, buf, len, flags, to, tolen);

	if ((nosigpipe) && (sigaction(SIGPIPE, &oact, NULL) < 0))
		lx_err_fatal(
		    gettext("%s: could not reset SIGPIPE handler to "
		    "emulate LX_MSG_NOSIGNAL"), "sendto()");

	if (r < 0) {
		/*
		 * according to the man page and LTP, the expected error in
		 * this case is EPIPE.
		 */
		if (errno == ENOTCONN)
			return (-EPIPE);
		else
			return (-errno);
	}
	return (r);
}
Beispiel #21
0
ptrdiff_t
doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
	const char *format_end, va_list ap)
{
  const char *fmt = format;	/* Pointer into format string.  */
  char *bufptr = buffer;	/* Pointer into output buffer.  */

  /* Use this for sprintf unless we need something really big.  */
  char tembuf[DBL_MAX_10_EXP + 100];

  /* Size of sprintf_buffer.  */
  ptrdiff_t size_allocated = sizeof (tembuf);

  /* Buffer to use for sprintf.  Either tembuf or same as BIG_BUFFER.  */
  char *sprintf_buffer = tembuf;

  /* Buffer we have got with malloc.  */
  char *big_buffer = NULL;

  enum text_quoting_style quoting_style = text_quoting_style ();
  ptrdiff_t tem = -1;
  char *string;
  char fixed_buffer[20];	/* Default buffer for small formatting. */
  char *fmtcpy;
  int minlen;
  char charbuf[MAX_MULTIBYTE_LENGTH + 1];	/* Used for %c.  */
  USE_SAFE_ALLOCA;

  if (format_end == 0)
    format_end = format + strlen (format);

  fmtcpy = (format_end - format < sizeof (fixed_buffer) - 1
	    ? fixed_buffer
	    : SAFE_ALLOCA (format_end - format + 1));

  bufsize--;

  /* Loop until end of format string or buffer full. */
  while (fmt < format_end && bufsize > 0)
    {
      char const *fmt0 = fmt;
      char fmtchar = *fmt++;
      if (fmtchar == '%')
	{
	  ptrdiff_t size_bound = 0;
	  ptrdiff_t width;  /* Columns occupied by STRING on display.  */
	  enum {
	    pDlen = sizeof pD - 1,
	    pIlen = sizeof pI - 1,
	    pMlen = sizeof pMd - 2
	  };
	  enum {
	    no_modifier, long_modifier, pD_modifier, pI_modifier, pM_modifier
	  } length_modifier = no_modifier;
	  static char const modifier_len[] = { 0, 1, pDlen, pIlen, pMlen };
	  int maxmlen = max (max (1, pDlen), max (pIlen, pMlen));
	  int mlen;

	  /* Copy this one %-spec into fmtcpy.  */
	  string = fmtcpy;
	  *string++ = '%';
	  while (fmt < format_end)
	    {
	      *string++ = *fmt;
	      if ('0' <= *fmt && *fmt <= '9')
		{
		  /* Get an idea of how much space we might need.
		     This might be a field width or a precision; e.g.
		     %1.1000f and %1000.1f both might need 1000+ bytes.
		     Parse the width or precision, checking for overflow.  */
		  ptrdiff_t n = *fmt - '0';
		  while (fmt + 1 < format_end
			 && '0' <= fmt[1] && fmt[1] <= '9')
		    {
		      /* Avoid ptrdiff_t, size_t, and int overflow, as
			 many sprintfs mishandle widths greater than INT_MAX.
			 This test is simple but slightly conservative: e.g.,
			 (INT_MAX - INT_MAX % 10) is reported as an overflow
			 even when it's not.  */
		      if (n >= min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX)) / 10)
			error ("Format width or precision too large");
		      n = n * 10 + fmt[1] - '0';
		      *string++ = *++fmt;
		    }

		  if (size_bound < n)
		    size_bound = n;
		}
	      else if (! (*fmt == '-' || *fmt == ' ' || *fmt == '.'
			  || *fmt == '+'))
		break;
	      fmt++;
	    }

	  /* Check for the length modifiers in textual length order, so
	     that longer modifiers override shorter ones.  */
	  for (mlen = 1; mlen <= maxmlen; mlen++)
	    {
	      if (format_end - fmt < mlen)
		break;
	      if (mlen == 1 && *fmt == 'l')
		length_modifier = long_modifier;
	      if (mlen == pDlen && memcmp (fmt, pD, pDlen) == 0)
		length_modifier = pD_modifier;
	      if (mlen == pIlen && memcmp (fmt, pI, pIlen) == 0)
		length_modifier = pI_modifier;
	      if (mlen == pMlen && memcmp (fmt, pMd, pMlen) == 0)
		length_modifier = pM_modifier;
	    }

	  mlen = modifier_len[length_modifier];
	  memcpy (string, fmt + 1, mlen);
	  string += mlen;
	  fmt += mlen;
	  *string = 0;

	  /* Make the size bound large enough to handle floating point formats
	     with large numbers.  */
	  if (size_bound > min (PTRDIFF_MAX, SIZE_MAX) - DBL_MAX_10_EXP - 50)
	    error ("Format width or precision too large");
	  size_bound += DBL_MAX_10_EXP + 50;

	  /* Make sure we have that much.  */
	  if (size_bound > size_allocated)
	    {
	      if (big_buffer)
		xfree (big_buffer);
	      big_buffer = xmalloc (size_bound);
	      sprintf_buffer = big_buffer;
	      size_allocated = size_bound;
	    }
	  minlen = 0;
	  switch (*fmt++)
	    {
	    default:
	      error ("Invalid format operation %s", fmtcpy);

/*	    case 'b': */
	    case 'l':
	    case 'd':
	      switch (length_modifier)
		{
		case no_modifier:
		  {
		    int v = va_arg (ap, int);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		case long_modifier:
		  {
		    long v = va_arg (ap, long);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		case pD_modifier:
		signed_pD_modifier:
		  {
		    ptrdiff_t v = va_arg (ap, ptrdiff_t);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		case pI_modifier:
		  {
		    EMACS_INT v = va_arg (ap, EMACS_INT);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		case pM_modifier:
		  {
		    intmax_t v = va_arg (ap, intmax_t);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		}
	      /* Now copy into final output, truncating as necessary.  */
	      string = sprintf_buffer;
	      goto doit;

	    case 'o':
	    case 'x':
	      switch (length_modifier)
		{
		case no_modifier:
		  {
		    unsigned v = va_arg (ap, unsigned);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		case long_modifier:
		  {
		    unsigned long v = va_arg (ap, unsigned long);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		case pD_modifier:
		  goto signed_pD_modifier;
		case pI_modifier:
		  {
		    EMACS_UINT v = va_arg (ap, EMACS_UINT);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		case pM_modifier:
		  {
		    uintmax_t v = va_arg (ap, uintmax_t);
		    tem = sprintf (sprintf_buffer, fmtcpy, v);
		  }
		  break;
		}
	      /* Now copy into final output, truncating as necessary.  */
	      string = sprintf_buffer;
	      goto doit;

	    case 'f':
	    case 'e':
	    case 'g':
	      {
		double d = va_arg (ap, double);
		tem = sprintf (sprintf_buffer, fmtcpy, d);
		/* Now copy into final output, truncating as necessary.  */
		string = sprintf_buffer;
		goto doit;
	      }

	    case 'S':
	      string[-1] = 's';
	    case 's':
	      if (fmtcpy[1] != 's')
		minlen = atoi (&fmtcpy[1]);
	      string = va_arg (ap, char *);
	      tem = strlen (string);
	      if (STRING_BYTES_BOUND < tem)
		error ("String for %%s or %%S format is too long");
	      width = strwidth (string, tem);
	      goto doit1;

	      /* Copy string into final output, truncating if no room.  */
	    doit:
	      eassert (0 <= tem);
	      /* Coming here means STRING contains ASCII only.  */
	      if (STRING_BYTES_BOUND < tem)
		error ("Format width or precision too large");
	      width = tem;
	    doit1:
	      /* We have already calculated:
		 TEM -- length of STRING,
		 WIDTH -- columns occupied by STRING when displayed, and
		 MINLEN -- minimum columns of the output.  */
	      if (minlen > 0)
		{
		  while (minlen > width && bufsize > 0)
		    {
		      *bufptr++ = ' ';
		      bufsize--;
		      minlen--;
		    }
		  minlen = 0;
		}
	      if (tem > bufsize)
		{
		  /* Truncate the string at character boundary.  */
		  tem = bufsize;
		  do
		    {
		      tem--;
		      if (CHAR_HEAD_P (string[tem]))
			{
			  if (BYTES_BY_CHAR_HEAD (string[tem]) <= bufsize - tem)
			    tem = bufsize;
			  break;
			}
		    }
		  while (tem != 0);

		  memcpy (bufptr, string, tem);
		  bufptr[tem] = 0;
		  /* Trigger exit from the loop, but make sure we
		     return to the caller a value which will indicate
		     that the buffer was too small.  */
		  bufptr += bufsize;
		  bufsize = 0;
		  continue;
		}
	      memcpy (bufptr, string, tem);
	      bufptr += tem;
	      bufsize -= tem;
	      if (minlen < 0)
		{
		  while (minlen < - width && bufsize > 0)
		    {
		      *bufptr++ = ' ';
		      bufsize--;
		      minlen++;
		    }
		  minlen = 0;
		}
	      continue;

	    case 'c':
	      {
		int chr = va_arg (ap, int);
		tem = CHAR_STRING (chr, (unsigned char *) charbuf);
		string = charbuf;
		string[tem] = 0;
		width = strwidth (string, tem);
		if (fmtcpy[1] != 'c')
		  minlen = atoi (&fmtcpy[1]);
		goto doit1;
	      }

	    case '%':
	      fmt--;    /* Drop thru and this % will be treated as normal */
	    }
	}

      char const *src;
      ptrdiff_t srclen;
      if (quoting_style == CURVE_QUOTING_STYLE && fmtchar == '`')
	src = uLSQM, srclen = sizeof uLSQM - 1;
      else if (quoting_style == CURVE_QUOTING_STYLE && fmtchar == '\'')
	src = uRSQM, srclen = sizeof uRSQM - 1;
      else if (quoting_style == STRAIGHT_QUOTING_STYLE && fmtchar == '`')
	src = "'", srclen = 1;
      else
	{
	  while (fmt < format_end && !CHAR_HEAD_P (*fmt))
	    fmt++;
	  src = fmt0, srclen = fmt - fmt0;
	}

      if (bufsize < srclen)
	{
	  /* Truncate, but return value that will signal to caller
	     that the buffer was too small.  */
	  do
	    *bufptr++ = '\0';
	  while (--bufsize != 0);
	}
      else
	{
	  do
	    *bufptr++ = *src++;
	  while (--srclen != 0);
	}
    }
Beispiel #22
0
static int
lx_getsockname(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct sockaddr *name = NULL;
	socklen_t namelen, namelen_orig;

	if (uucopy((void *)args[2], &namelen, sizeof (socklen_t)) != 0)
		return (-errno);
	namelen_orig = namelen;

	lx_debug("\tgetsockname(%d, 0x%p, 0x%p (=%d))",
	    sockfd, args[1], args[2], namelen);

	if (namelen > 0) {
		if ((name = SAFE_ALLOCA(namelen)) == NULL)
			return (-EINVAL);
		bzero(name, namelen);
	}

	if (getsockname(sockfd, name, &namelen) < 0)
		return (-errno);

	/*
	 * The caller might be asking for the name for an AF_NETLINK socket
	 * which we're emulating as a unix socket. Check if that is the case
	 * and if so, construct a made up name for this socket.
	 */
	if (namelen_orig < namelen && name->sa_family == AF_UNIX &&
	    namelen_orig == sizeof (lx_sockaddr_nl_t)) {
		struct sockaddr *tname;
		socklen_t tlen = sizeof (struct sockaddr_un);

		if ((tname = SAFE_ALLOCA(tlen)) != NULL) {
			bzero(tname, tlen);
			if (getsockname(sockfd, tname, &tlen) >= 0 &&
			    strcmp(tname->sa_data, NETLINK_NAME) == 0) {
				/*
				 * This is indeed our netlink socket, make the
				 * name look correct.
				 */
				lx_sockaddr_nl_t *p =
				    (lx_sockaddr_nl_t *)(void *)name;

				bzero(name, namelen_orig);
				p->nl_family = LX_AF_NETLINK;
				p->nl_pid = getpid();
				namelen = namelen_orig;
			}
		}
	}

	/*
	 * If the name that getsockname() want's to return is larger
	 * than namelen, getsockname() will copy out the maximum amount
	 * of data possible and then update namelen to indicate the
	 * actually size of all the data that it wanted to copy out.
	 */
	if (uucopy(name, (void *)args[1], namelen_orig) != 0)
		return (-errno);
	if (uucopy(&namelen, (void *)args[2], sizeof (socklen_t)) != 0)
		return (-errno);

	return (0);
}
Beispiel #23
0
static Lisp_Object
simple_dialog_show (struct frame *f, Lisp_Object contents, Lisp_Object header)
{
  int answer;
  UINT type;
  Lisp_Object lispy_answer = Qnil, temp = XCAR (contents);

  type = MB_YESNO;

  /* Since we only handle Yes/No dialogs, and we already checked
     is_simple_dialog, we don't need to worry about checking contents
     to see what type of dialog to use.  */

  /* Use Unicode if possible, so any language can be displayed.  */
  if (unicode_message_box)
    {
      WCHAR *text;
      const WCHAR *title;
      USE_SAFE_ALLOCA;

      if (STRINGP (temp))
	{
	  char *utf8_text = SSDATA (ENCODE_UTF_8 (temp));
	  /* Be pessimistic about the number of characters needed.
	     Remember characters outside the BMP will take more than
	     one utf16 word, so we cannot simply use the character
	     length of temp.  */
	  int utf8_len = strlen (utf8_text);
	  text = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
	  utf8to16 ((unsigned char *)utf8_text, utf8_len, text);
	}
      else
	{
	  text = (WCHAR *)L"";
	}

      if (NILP (header))
	{
	  title = L"Question";
	  type |= MB_ICONQUESTION;
	}
      else
	{
	  title = L"Information";
	  type |= MB_ICONINFORMATION;
	}

      answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type);
      SAFE_FREE ();
    }
  else
    {
      const char *text, *title;

      /* Fall back on ANSI message box, but at least use system
	 encoding so questions representable by the system codepage
	 are encoded properly.  */
      if (STRINGP (temp))
	text = SSDATA (ENCODE_SYSTEM (temp));
      else
	text = "";

      if (NILP (header))
	{
	  title = "Question";
	  type |= MB_ICONQUESTION;
	}
      else
	{
	  title = "Information";
	  type |= MB_ICONINFORMATION;
	}

      answer = MessageBox (FRAME_W32_WINDOW (f), text, title, type);
    }

  if (answer == IDYES)
    lispy_answer = build_string ("Yes");
  else if (answer == IDNO)
    lispy_answer = build_string ("No");
  else
    Fsignal (Qquit, Qnil);

  for (temp = XCDR (contents); CONSP (temp); temp = XCDR (temp))
    {
      Lisp_Object item, name, value;
      item = XCAR (temp);
      if (CONSP (item))
	{
	  name = XCAR (item);
	  value = XCDR (item);
	}
      else
	{
	  name = item;
	  value = Qnil;
	}

      if (!NILP (Fstring_equal (name, lispy_answer)))
	{
	  return value;
	}
    }
  Fsignal (Qquit, Qnil);
  return Qnil;
}
Beispiel #24
0
static int
lx_bind(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct stat64 statbuf;
	struct sockaddr *name;
	socklen_t len;
	int r, r2, ret, tmperrno;
	int nlen;
	lx_addr_type_t type;
	struct stat sb;

	if ((nlen = calc_addr_size((struct sockaddr *)args[1], (int)args[2],
	    &type)) < 0)
		return (nlen);

	if ((name = SAFE_ALLOCA(nlen)) == NULL)
		return (-EINVAL);

	if ((r = convert_sockaddr(name, &len, (struct sockaddr *)args[1],
	    (socklen_t)args[2])) < 0)
		return (r);

	/*
	 * Linux abstract namespace unix sockets are simply socket that do not
	 * exist on the filesystem. We emulate them by changing their paths
	 * in convert_sockaddr so that they point real files names on the
	 * filesystem. Because in Linux they do not exist on the filesystem
	 * applications do not have to worry about deleting files, however in
	 * our filesystem based emulation we do. To solve this problem, we first
	 * check to see if the socket already exists before we create one. If it
	 * does we attempt to connect to it to see if it is in use, or just
	 * left over from a previous lx_bind call. If we are unable to connect,
	 * we assume it is not in use and remove the file, then continue on
	 * as if the file never existed.
	 */
	if (type == lxa_abstract && stat(name->sa_data, &sb) == 0 &&
	    S_ISSOCK(sb.st_mode)) {
		if ((r2 = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
			return (-ENOSR);
		ret = connect(r2, name, len);
		tmperrno = errno;
		if (close(r2) < 0)
			return (-EINVAL);

		/*
		 * if we can't connect to the socket, assume no one is using it
		 * and remove it, otherwise assume it is in use and return
		 * EADDRINUSE.
		 */
		if ((ret < 0) && (tmperrno == ECONNREFUSED)) {
			if (unlink(name->sa_data) < 0) {
				return (-EADDRINUSE);
			}
		} else {
			return (-EADDRINUSE);
		}
	}

	lx_debug("\tbind(%d, 0x%p, %d)", sockfd, name, len);

	if (name->sa_family == AF_UNIX)
		lx_debug("\t\tAF_UNIX, path = %s", name->sa_data);

	r = bind(sockfd, name, len);

	/*
	 * Linux returns EADDRINUSE for attempts to bind to UNIX domain
	 * sockets that aren't sockets.
	 */
	if ((r < 0) && (errno == EINVAL) && (name->sa_family == AF_UNIX) &&
	    ((stat64(name->sa_data, &statbuf) == 0) &&
	    (!S_ISSOCK(statbuf.st_mode))))
		return (-EADDRINUSE);

	/*
	 * Now that the dummy netlink socket is setup, remove it to prevent
	 * future name collisions.
	 */
	if (type == lxa_netlink && r >= 0)
		(void) unlink(name->sa_data);

	return ((r < 0) ? -errno : r);
}
Beispiel #25
0
static int
lx_recvmsg(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct lx_msghdr msg;
	struct lx_msghdr *msgp = (struct lx_msghdr *)args[1];
	struct cmsghdr *cmsg = NULL;
	int flags = (int)args[2];
	int r, err;

	int nosigpipe = flags & LX_MSG_NOSIGNAL;
	struct sigaction newact, oact;

	lx_debug("\trecvmsg(%d, 0x%p, 0x%x)", sockfd, msgp, flags);

	flags = convert_sockflags(flags);

	if ((uucopy(msgp, &msg, sizeof (msg))) != 0)
		return (-errno);

	/*
	 * If we are expecting to have to convert any control messages,
	 * then we should receive them into our address space instead of
	 * the app's.
	 */
	if (msg.msg_control != NULL) {
		cmsg = msg.msg_control;
		if (msg.msg_controllen == 0) {
			msg.msg_control = NULL;
		} else {
			msg.msg_control = SAFE_ALLOCA(msg.msg_controllen);
			if (msg.msg_control == NULL)
				return (-EINVAL);
		}
	}

	/*
	 * If nosigpipe is set, we want to emulate the Linux action of
	 * not sending a SIGPIPE to the caller if the remote socket has
	 * already been closed.
	 *
	 * As SIGPIPE is a directed signal sent only to the thread that
	 * performed the action, we can emulate this behavior by momentarily
	 * resetting the action for SIGPIPE to SIG_IGN, performing the socket
	 * call, and resetting the action back to its previous value.
	 */
	if (nosigpipe) {
		newact.sa_handler = SIG_IGN;
		newact.sa_flags = 0;
		(void) sigemptyset(&newact.sa_mask);

		if (sigaction(SIGPIPE, &newact, &oact) < 0)
			lx_err_fatal(gettext(
			    "%s: could not ignore SIGPIPE to emulate "
			    "LX_MSG_NOSIGNAL"), "recvmsg()");
	}

	r = _so_recvmsg(sockfd, (struct msghdr *)&msg, flags | MSG_XPG4_2);

	if ((nosigpipe) && (sigaction(SIGPIPE, &oact, NULL) < 0))
		lx_err_fatal(
		    gettext("%s: could not reset SIGPIPE handler to "
		    "emulate LX_MSG_NOSIGNAL"), "recvmsg()");

	if (r >= 0 && msg.msg_controllen >= sizeof (struct cmsghdr)) {
		/*
		 * If there are control messages bundled in this message,
		 * we need to convert them from Linux to Solaris.
		 */
		if ((err = convert_cmsgs(SOL_TO_LX, &msg, "recvmsg()")) != 0)
			return (-err);

		if ((uucopy(msg.msg_control, cmsg, msg.msg_controllen)) != 0)
			return (-errno);
	}

	msg.msg_control = cmsg;

	/*
	 * A handful of the values in the msghdr are set by the recvmsg()
	 * call, so copy their values back to the caller.  Rather than iterate,
	 * just copy the whole structure back.
	 */
	if (uucopy(&msg, msgp, sizeof (msg)) != 0)
		return (-errno);

	return ((r < 0) ? -errno : r);
}
Beispiel #26
0
static int
lx_getsockopt(ulong_t *args)
{
	int sockfd = (int)args[0];
	int level = (int)args[1];
	int optname = (int)args[2];
	void *optval = (void *)args[3];
	int *optlenp = (int *)args[4];
	int r;

	lx_debug("\tgetsockopt(%d, %d, %d, 0x%p, 0x%p)", sockfd, level, optname,
	    optval, optlenp);

	/*
	 * According to the Linux man page, a NULL optval should indicate
	 * (as in Solaris) that no return value is expected.  Instead, it
	 * actually triggers an EFAULT error.
	 */
	if (optval == NULL)
		return (-EFAULT);

	/*
	 * Do a table lookup of the Solaris equivalent of the given option
	 */
	if (level < IPPROTO_IP || level >= IPPROTO_TAB_SIZE)
		return (-EOPNOTSUPP);

	if (ltos_proto_opts[level].maxentries == 0 ||
	    optname <= 0 || optname >= (ltos_proto_opts[level].maxentries))
		return (-ENOPROTOOPT);

	if (((level == LX_SOL_SOCKET) && (optname == LX_SO_PASSCRED)) ||
	    ((level == IPPROTO_TCP) && (optname == LX_TCP_CORK))) {
		/*
		 * Linux sets LX_SO_PASSCRED when it wants to send credentials
		 * over a socket. Since we do not support it, it is never set
		 * and we return 0.
		 *
		 * We don't support TCP_CORK but some apps rely on it.  So,
		 * rather than return an error we just return 0.  This
		 * isn't exactly a lie, since this option really isn't set,
		 * but it's not the whole truth either.  Fortunately, we
		 * aren't under oath.
		 */
		r = 0;
		if (uucopy(&r, optval, sizeof (int)) != 0)
			return (-errno);
		r = sizeof (int);
		if (uucopy(&r, optlenp, sizeof (int)) != 0)
			return (-errno);
		return (0);
	}
	if ((level == LX_SOL_SOCKET) && (optname == LX_SO_PEERCRED)) {
		struct lx_ucred	lx_ucred;
		ucred_t		*ucp;

		/*
		 * We don't support SO_PEERCRED, but we do have equivalent
		 * functionality in getpeerucred() so invoke that here.
		 */

		/* Verify there's going to be enough room for the results. */
		if (uucopy(optlenp, &r, sizeof (int)) != 0)
			return (-errno);
		if (r < sizeof (struct lx_ucred))
			return (-EOVERFLOW);

		/*
		 * We allocate a ucred_t ourselves rather than allow
		 * getpeerucred() to do it for us because getpeerucred()
		 * uses malloc(3C) and we'd rather use SAFE_ALLOCA().
		 */
		if ((ucp = (ucred_t *)SAFE_ALLOCA(ucred_size())) == NULL)
			return (-ENOMEM);

		/* Get the credential for the remote end of this socket. */
		if (getpeerucred(sockfd, &ucp) != 0)
			return (-errno);
		if (((lx_ucred.lxu_pid = ucred_getpid(ucp)) == -1) ||
		    ((lx_ucred.lxu_uid = ucred_geteuid(ucp)) == (uid_t)-1) ||
		    ((lx_ucred.lxu_gid = ucred_getegid(ucp)) == (gid_t)-1)) {
			return (-errno);
		}

		/* Copy out the results. */
		if ((uucopy(&lx_ucred, optval, sizeof (lx_ucred))) != 0)
			return (-errno);
		r = sizeof (lx_ucred);
		if ((uucopy(&r, optlenp, sizeof (int))) != 0)
			return (-errno);
		return (0);
	}

	optname = ltos_proto_opts[level].proto[optname];

	if (optname == OPTNOTSUP)
		return (-ENOPROTOOPT);

	if (level == LX_SOL_SOCKET)
		level = SOL_SOCKET;

	r = getsockopt(sockfd, level, optname, optval, optlenp);

	return ((r < 0) ? -errno : r);
}
Beispiel #27
0
static void
do_direct_scrolling (struct frame *frame, struct glyph_matrix *current_matrix,
		     struct matrix_elt *cost_matrix, int window_size,
		     int unchanged_at_top)
{
  struct matrix_elt *p;
  int i, j;
  USE_SAFE_ALLOCA;

  /* A queue of deletions and insertions to be performed.  */
  struct alt_queue { int count, pos, window; };
  struct alt_queue *queue_start;
  SAFE_NALLOCA (queue_start, 1, window_size);
  struct alt_queue *queue = queue_start;

  /* True if a terminal window has been set with set_terminal_window.  */
  bool terminal_window_p = 0;

  /* If true, a write has been selected, allowing either an insert or a
     delete to be selected next.  If false, a delete cannot be selected
     unless j < i, and an insert cannot be selected unless i < j.
     This corresponds to a similar restriction (with the ordering
     reversed) in calculate_direct_scrolling, which is intended to
     ensure that lines marked as inserted will be blank. */
  bool write_follows_p = 1;

  /* For each row in the new matrix what row of the old matrix it is.  */
  int *copy_from;
  SAFE_NALLOCA (copy_from, 1, window_size);

  /* Non-zero for each row in the new matrix that is retained from the
     old matrix.  Lines not retained are empty.  */
  char *retained_p = SAFE_ALLOCA (window_size);

  memset (retained_p, 0, window_size * sizeof (char));

  /* Perform some sanity checks when GLYPH_DEBUG is on.  */
  CHECK_MATRIX (current_matrix);

  /* We are working on the line range UNCHANGED_AT_TOP ...
     UNCHANGED_AT_TOP + WINDOW_SIZE (not including) in CURRENT_MATRIX.
     We step through lines in this range from the end to the start.  I
     is an index into new lines, j an index into old lines.  The cost
     matrix determines what to do for ranges of indices.

     If i is decremented without also decrementing j, this corresponds
     to inserting empty lines in the result.  If j is decremented
     without also decrementing i, this corresponds to omitting these
     lines in the new rows, i.e. rows are deleted.  */
  i = j = window_size;

  while (i > 0 || j > 0)
    {
      p = cost_matrix + i * (window_size + 1) + j;

      if (p->insertcost < p->writecost
	  && p->insertcost < p->deletecost
	  && (write_follows_p || i < j))
	{
	  /* Insert is cheaper than deleting or writing lines.  Leave
	     a hole in the result display that will be filled with
	     empty lines when the queue is emptied.  */
	  queue->count = 0;
	  queue->window = i;
	  queue->pos = i - p->insertcount;
	  ++queue;

	  i -= p->insertcount;
	  write_follows_p = 0;
	}
      else if (p->deletecost < p->writecost
	       && (write_follows_p || i > j))
	{
	  /* Deleting lines is cheaper.  By decrementing J, omit
	     deletecount lines from the original.  */
	  write_follows_p = 0;
	  j -= p->deletecount;
	}
      else
	{
	  /* One or more lines should be written.  In the direct
	     scrolling method we do this by scrolling the lines to the
	     place they belong.  */
	  int n_to_write = p->writecount;
	  write_follows_p = 1;
	  eassert (n_to_write > 0);

	  if (i > j)
	    {
	      /* Immediately insert lines */
	      set_terminal_window (frame, i + unchanged_at_top);
	      terminal_window_p = 1;
	      ins_del_lines (frame, j - n_to_write + unchanged_at_top, i - j);
	    }
	  else if (i < j)
	    {
	      /* Queue the deletion of a group of lines */
	      queue->pos = i - n_to_write + unchanged_at_top;
	      queue->window = j + unchanged_at_top;
	      queue->count = i - j;
	      ++queue;
	    }

	  while (n_to_write > 0)
	    {
	      --i, --j, --n_to_write;
	      copy_from[i] = j;
	      retained_p[j] = 1;
	    }
	}
    }

  /* Do queued operations.  */
  if (queue > queue_start)
    {
      int next = -1;

      do
	{
	  --queue;
	  if (queue->count)
	    {
	      set_terminal_window (frame, queue->window);
	      terminal_window_p = 1;
	      ins_del_lines (frame, queue->pos, queue->count);
	    }
	  else
	    {
	      for (j = queue->window - 1; j >= queue->pos; --j)
		{
		  while (retained_p[++next])
		    ;
		  copy_from[j] = next;
		}
	    }
	}
      while (queue > queue_start);
    }

  /* Now, for each row I in the range of rows we are working on,
     copy_from[i] gives the original line to copy to I, and
     retained_p[copy_from[i]] is zero if line I in the new display is
     empty.  */
  mirrored_line_dance (current_matrix, unchanged_at_top, window_size,
		       copy_from, retained_p);

  if (terminal_window_p)
    set_terminal_window (frame, 0);
  SAFE_FREE ();
}
Beispiel #28
0
Lisp_Object
get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
{
  char *from, *to, *name, *p, *p1;
  int fd;
  int offset;
  EMACS_INT position;
  Lisp_Object file, tem, pos;
  ptrdiff_t count;
  USE_SAFE_ALLOCA;

  if (INTEGERP (filepos))
    {
      file = Vdoc_file_name;
      pos = filepos;
    }
  else if (CONSP (filepos))
    {
      file = XCAR (filepos);
      pos = XCDR (filepos);
    }
  else
    return Qnil;

  position = eabs (XINT (pos));

  if (!STRINGP (Vdoc_directory))
    return Qnil;

  if (!STRINGP (file))
    return Qnil;

  /* Put the file name in NAME as a C string.
     If it is relative, combine it with Vdoc_directory.  */

  tem = Ffile_name_absolute_p (file);
  file = ENCODE_FILE (file);
  Lisp_Object docdir
    = NILP (tem) ? ENCODE_FILE (Vdoc_directory) : empty_unibyte_string;
  ptrdiff_t docdir_sizemax = SBYTES (docdir) + 1;
#ifndef CANNOT_DUMP
  docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc);
#endif
  name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file));
  lispstpcpy (lispstpcpy (name, docdir), file);

  fd = emacs_open (name, O_RDONLY, 0);
  if (fd < 0)
    {
#ifndef CANNOT_DUMP
      if (!NILP (Vpurify_flag))
	{
	  /* Preparing to dump; DOC file is probably not installed.
	     So check in ../etc.  */
	  lispstpcpy (stpcpy (name, sibling_etc), file);

	  fd = emacs_open (name, O_RDONLY, 0);
	}
#endif
      if (fd < 0)
	{
	  if (errno == EMFILE || errno == ENFILE)
	    report_file_error ("Read error on documentation file", file);

	  SAFE_FREE ();
	  AUTO_STRING (cannot_open, "Cannot open doc string file \"");
	  AUTO_STRING (quote_nl, "\"\n");
	  return concat3 (cannot_open, file, quote_nl);
	}
    }
  count = SPECPDL_INDEX ();
  record_unwind_protect_int (close_file_unwind, fd);

  /* Seek only to beginning of disk block.  */
  /* Make sure we read at least 1024 bytes before `position'
     so we can check the leading text for consistency.  */
  offset = min (position, max (1024, position % (8 * 1024)));
  if (TYPE_MAXIMUM (off_t) < position
      || lseek (fd, position - offset, 0) < 0)
    error ("Position %"pI"d out of range in doc string file \"%s\"",
	   position, name);

  /* Read the doc string into get_doc_string_buffer.
     P points beyond the data just read.  */

  p = get_doc_string_buffer;
  while (1)
    {
      ptrdiff_t space_left = (get_doc_string_buffer_size - 1
			      - (p - get_doc_string_buffer));
      int nread;

      /* Allocate or grow the buffer if we need to.  */
      if (space_left <= 0)
	{
	  ptrdiff_t in_buffer = p - get_doc_string_buffer;
	  get_doc_string_buffer
	    = xpalloc (get_doc_string_buffer, &get_doc_string_buffer_size,
		       16 * 1024, -1, 1);
	  p = get_doc_string_buffer + in_buffer;
	  space_left = (get_doc_string_buffer_size - 1
			- (p - get_doc_string_buffer));
	}

      /* Read a disk block at a time.
         If we read the same block last time, maybe skip this?  */
      if (space_left > 1024 * 8)
	space_left = 1024 * 8;
      nread = emacs_read (fd, p, space_left);
      if (nread < 0)
	report_file_error ("Read error on documentation file", file);
      p[nread] = 0;
      if (!nread)
	break;
      if (p == get_doc_string_buffer)
	p1 = strchr (p + offset, '\037');
      else
	p1 = strchr (p, '\037');
      if (p1)
	{
	  *p1 = 0;
	  p = p1;
	  break;
	}
      p += nread;
    }
  unbind_to (count, Qnil);
  SAFE_FREE ();

  /* Sanity checking.  */
  if (CONSP (filepos))
    {
      int test = 1;
      /* A dynamic docstring should be either at the very beginning of a "#@
	 comment" or right after a dynamic docstring delimiter (in case we
	 pack several such docstrings within the same comment).  */
      if (get_doc_string_buffer[offset - test] != '\037')
	{
	  if (get_doc_string_buffer[offset - test++] != ' ')
	    return Qnil;
	  while (get_doc_string_buffer[offset - test] >= '0'
		 && get_doc_string_buffer[offset - test] <= '9')
	    test++;
	  if (get_doc_string_buffer[offset - test++] != '@'
	      || get_doc_string_buffer[offset - test] != '#')
	    return Qnil;
	}
    }
  else
    {
      int test = 1;
      if (get_doc_string_buffer[offset - test++] != '\n')
	return Qnil;
      while (get_doc_string_buffer[offset - test] > ' ')
	test++;
      if (get_doc_string_buffer[offset - test] != '\037')
	return Qnil;
    }

  /* Scan the text and perform quoting with ^A (char code 1).
     ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_.  */
  from = get_doc_string_buffer + offset;
  to = get_doc_string_buffer + offset;
  while (from != p)
    {
      if (*from == 1)
	{
	  int c;

	  from++;
	  c = *from++;
	  if (c == 1)
	    *to++ = c;
	  else if (c == '0')
	    *to++ = 0;
	  else if (c == '_')
	    *to++ = 037;
	  else
	    {
	      unsigned char uc = c;
	      error ("\
Invalid data in documentation file -- %c followed by code %03o",
		     1, uc);
	    }
	}
      else
	*to++ = *from++;
    }

  /* If DEFINITION, read from this buffer
     the same way we would read bytes from a file.  */
  if (definition)
    {
      read_bytecode_pointer = (unsigned char *) get_doc_string_buffer + offset;
      return Fread (Qlambda);
    }

  if (unibyte)
    return make_unibyte_string (get_doc_string_buffer + offset,
				to - (get_doc_string_buffer + offset));
  else
    {
      /* The data determines whether the string is multibyte.  */
      ptrdiff_t nchars
	= multibyte_chars_in_text (((unsigned char *) get_doc_string_buffer
				    + offset),
				   to - (get_doc_string_buffer + offset));
      return make_string_from_bytes (get_doc_string_buffer + offset,
				     nchars,
				     to - (get_doc_string_buffer + offset));
    }
}
Beispiel #29
0
static int
lx_sendmsg(ulong_t *args)
{
	int sockfd = (int)args[0];
	struct lx_msghdr msg;
	struct cmsghdr *cmsg;
	int flags = (int)args[2];
	int r;

	int nosigpipe = flags & LX_MSG_NOSIGNAL;
	struct sigaction newact, oact;

	lx_debug("\tsendmsg(%d, 0x%p, 0x%x)", sockfd, (void *)args[1], flags);

	flags = convert_sockflags(flags);

	if ((uucopy((void *)args[1], &msg, sizeof (msg))) != 0)
		return (-errno);

	/*
	 * If there are control messages bundled in this message, we need
	 * to convert them from Linux to Solaris.
	 */
	if (msg.msg_control != NULL) {
		if (msg.msg_controllen == 0) {
			cmsg = NULL;
		} else {
			cmsg = SAFE_ALLOCA(msg.msg_controllen);
			if (cmsg == NULL)
				return (-EINVAL);
		}
		if ((uucopy(msg.msg_control, cmsg, msg.msg_controllen)) != 0)
			return (-errno);
		msg.msg_control = cmsg;
		if ((r = convert_cmsgs(LX_TO_SOL, &msg, "sendmsg()")) != 0)
			return (-r);
	}

	/*
	 * If nosigpipe is set, we want to emulate the Linux action of
	 * not sending a SIGPIPE to the caller if the remote socket has
	 * already been closed.
	 *
	 * As SIGPIPE is a directed signal sent only to the thread that
	 * performed the action, we can emulate this behavior by momentarily
	 * resetting the action for SIGPIPE to SIG_IGN, performing the socket
	 * call, and resetting the action back to its previous value.
	 */
	if (nosigpipe) {
		newact.sa_handler = SIG_IGN;
		newact.sa_flags = 0;
		(void) sigemptyset(&newact.sa_mask);

		if (sigaction(SIGPIPE, &newact, &oact) < 0)
			lx_err_fatal(gettext(
			    "%s: could not ignore SIGPIPE to emulate "
			    "LX_MSG_NOSIGNAL"), "sendmsg()");
	}

	r = _so_sendmsg(sockfd, (struct msghdr *)&msg, flags | MSG_XPG4_2);

	if ((nosigpipe) && (sigaction(SIGPIPE, &oact, NULL) < 0))
		lx_err_fatal(
		    gettext("%s: could not reset SIGPIPE handler to "
		    "emulate LX_MSG_NOSIGNAL"), "sendmsg()");

	if (r < 0) {
		/*
		 * according to the man page and LTP, the expected error in
		 * this case is EPIPE.
		 */
		if (errno == ENOTCONN)
			return (-EPIPE);
		else
			return (-errno);
	}

	return (r);
}
Beispiel #30
0
static int
add_menu_item (HMENU menu, widget_value *wv, HMENU item)
{
  UINT fuFlags;
  char *out_string, *p, *q;
  int return_value;
  size_t nlen, orig_len;
  USE_SAFE_ALLOCA;

  if (menu_separator_name_p (wv->name))
    {
      fuFlags = MF_SEPARATOR;
      out_string = NULL;
    }
  else
    {
      if (wv->enabled)
	fuFlags = MF_STRING;
      else
	fuFlags = MF_STRING | MF_GRAYED;

      if (wv->key != NULL)
	{
	  out_string = SAFE_ALLOCA (strlen (wv->name) + strlen (wv->key) + 2);
	  p = stpcpy (out_string, wv->name);
	  p = stpcpy (p, "\t");
	  strcpy (p, wv->key);
	}
      else
	out_string = (char *)wv->name;

      /* Quote any special characters within the menu item's text and
	 key binding.  */
      nlen = orig_len = strlen (out_string);
      if (unicode_append_menu)
        {
          /* With UTF-8, & cannot be part of a multibyte character.  */
          for (p = out_string; *p; p++)
            {
              if (*p == '&')
                nlen++;
            }
        }
#ifndef NTGUI_UNICODE
      else
        {
          /* If encoded with the system codepage, use multibyte string
             functions in case of multibyte characters that contain '&'.  */
          for (p = out_string; *p; p = _mbsinc (p))
            {
              if (_mbsnextc (p) == '&')
                nlen++;
            }
        }
#endif /* !NTGUI_UNICODE */

      if (nlen > orig_len)
        {
          p = out_string;
          out_string = SAFE_ALLOCA (nlen + 1);
          q = out_string;
          while (*p)
            {
              if (unicode_append_menu)
                {
                  if (*p == '&')
                    *q++ = *p;
                  *q++ = *p++;
                }
#ifndef NTGUI_UNICODE
              else
                {
                  if (_mbsnextc (p) == '&')
                    {
                      _mbsncpy (q, p, 1);
                      q = _mbsinc (q);
                    }
                  _mbsncpy (q, p, 1);
                  p = _mbsinc (p);
                  q = _mbsinc (q);
                }
#endif /* !NTGUI_UNICODE */
            }
          *q = '\0';
        }

      if (item != NULL)
	fuFlags = MF_POPUP;
      else if (wv->title || wv->call_data == 0)
	{
	  /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
	     we can't deallocate the memory otherwise.  */
	  if (get_menu_item_info)
	    {
              out_string = (char *) local_alloc (strlen (wv->name) + 1);
              strcpy (out_string, wv->name);
#ifdef MENU_DEBUG
	      DebPrint ("Menu: allocating %ld for owner-draw", out_string);
#endif
	      fuFlags = MF_OWNERDRAW | MF_DISABLED;
	    }
	  else
	    fuFlags = MF_DISABLED;
	}

      /* Draw radio buttons and tickboxes. */
      else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
				wv->button_type == BUTTON_TYPE_RADIO))
	fuFlags |= MF_CHECKED;
      else
	fuFlags |= MF_UNCHECKED;
    }

  if (unicode_append_menu && out_string)
    {
      /* Convert out_string from UTF-8 to UTF-16-LE.  */
      int utf8_len = strlen (out_string);
      WCHAR * utf16_string;
      if (fuFlags & MF_OWNERDRAW)
	utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
      else
	utf16_string = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));

      utf8to16 ((unsigned char *)out_string, utf8_len, utf16_string);
      return_value = unicode_append_menu (menu, fuFlags,
					  item != NULL ? (UINT_PTR) item
					    : (UINT_PTR) wv->call_data,
					  utf16_string);

#ifndef NTGUI_UNICODE /* Fallback does not apply when always UNICODE */
      if (!return_value)
	{
	  /* On W9x/ME, Unicode menus are not supported, though AppendMenuW
	     apparently does exist at least in some cases and appears to be
	     stubbed out to do nothing.  out_string is UTF-8, but since
	     our standard menus are in English and this is only going to
	     happen the first time a menu is used, the encoding is
	     of minor importance compared with menus not working at all.  */
	  return_value =
	    AppendMenu (menu, fuFlags,
			item != NULL ? (UINT_PTR) item: (UINT_PTR) wv->call_data,
			out_string);
	  /* Don't use Unicode menus in future, unless this is Windows
	     NT or later, where a failure of AppendMenuW does NOT mean
	     Unicode menus are unsupported.  */
	  if (osinfo_cache.dwPlatformId != VER_PLATFORM_WIN32_NT)
	    unicode_append_menu = NULL;
	}
#endif /* NTGUI_UNICODE */

      if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
	local_free (out_string);
    }
  else
    {
      return_value =
	AppendMenu (menu,
		    fuFlags,
		    item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data,
		    out_string );
    }

  /* This must be done after the menu item is created.  */
  if (!wv->title && wv->call_data != 0)
    {
      if (set_menu_item_info)
	{
	  MENUITEMINFO info;
	  memset (&info, 0, sizeof (info));
	  info.cbSize = sizeof (info);
	  info.fMask = MIIM_DATA;

	  /* Set help string for menu item.  Leave it as a pointer to
	     a Lisp_String until it is ready to be displayed, since GC
	     can happen while menus are active.  */
	  if (!NILP (wv->help))
	    {
	      /* We use XUNTAG below because in a 32-bit build
		 --with-wide-int we cannot pass a Lisp_Object
		 via a DWORD member of MENUITEMINFO.  */
	      /* As of Jul-2012, w32api headers say that dwItemData
		 has DWORD type, but that's a bug: it should actually
		 be ULONG_PTR, which is correct for 32-bit and 64-bit
		 Windows alike.  MSVC headers get it right; hopefully,
		 MinGW headers will, too.  */
	      eassert (STRINGP (wv->help));
	      info.dwItemData = (ULONG_PTR) XUNTAG (wv->help, Lisp_String);
	    }
	  if (wv->button_type == BUTTON_TYPE_RADIO)
	    {
	      /* CheckMenuRadioItem allows us to differentiate TOGGLE and
		 RADIO items, but is not available on NT 3.51 and earlier.  */
	      info.fMask |= MIIM_TYPE | MIIM_STATE;
	      info.fType = MFT_RADIOCHECK | MFT_STRING;
	      info.dwTypeData = out_string;
	      info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
	    }

	  set_menu_item_info (menu,
			      item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data,
			      FALSE, &info);
	}
    }
  SAFE_FREE ();
  return return_value;
}