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); }
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); }
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 (); } }
/* * 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); }
/* * 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); } }
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); }
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; }
/* 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); }
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); }
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 (); } }
/* * 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); }
/* 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 (); }
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); }
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); }
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); }
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 (); }
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)); } }
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); }
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); }
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); }
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); } }
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); }
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; }
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); }
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); }
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); }
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 (); }
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)); } }
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); }
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; }