view src/unexsunos4.c @ 1721:6ba3bca4c3de

* frame.h (struct frame): New fields `can_have_scrollbars' and `has_vertical_scrollbars'. (FRAME_CAN_HAVE_SCROLLBARS, FRAME_HAS_VERTICAL_SCROLLBARS): New accessors, for both the MULTI_FRAME and non-MULTI_FRAME. (VERTICAL_SCROLLBAR_WIDTH, WINDOW_VERTICAL_SCROLLBAR, WINDOW_VERTICAL_SCROLLBAR_COLUMN, WINDOW_VERTICAL_SCROLLBAR_HEIGHT): New macros. * window.h (struct window): New field `vertical_scrollbar'. * xterm.h (struct x_display): vertical_scrollbars, judge_timestamp, vertical_scrollbar_extra: New fields. (struct scrollbar): New struct. (VERTICAL_SCROLLBAR_PIXEL_WIDTH, VERTICAL_SCROLLBAR_PIXEL_HEIGHT, VERTICAL_SCROLLBAR_LEFT_BORDER, VERTICAL_SCROLLBAR_RIGHT_BORDER, VERTICAL_SCROLLBAR_TOP_BORDER, VERTICAL_SCROLLBAR_BOTTOM_BORDER, CHAR_TO_PIXEL_WIDTH, CHAR_TO_PIXEL_HEIGHT, PIXEL_TO_CHAR_WIDTH, PIXEL_TO_CHAR_HEIGHT): New accessors and macros. * frame.c (make_frame): Initialize the `can_have_scrollbars' and `has_vertical_scrollbars' fields of the frame. * term.c (term_init): Note that TERMCAP terminals don't support scrollbars. (mouse_position_hook): Document new args. (set_vertical_scrollbar_hook, condemn_scrollbars_hook, redeem_scrollbar_hook, judge_scrollbars_hook): New hooks. * termhooks.h: Declare and document them. (enum scrollbar_part): New type. (struct input_event): Describe the new form of the scrollbar_click event type. Change `part' from a Lisp_Object to an enum scrollbar_part. Add a new field `scrollbar'. * keyboard.c (kbd_buffer_get_event): Pass appropriate new parameters to *mouse_position_hook, and make_lispy_movement. * xfns.c (x_set_vertical_scrollbar): New function. (x_figure_window_size): Use new macros to calculate frame size. (Fx_create_frame): Note that X Windows frames do support scroll bars. Default to "yes". * xterm.c: #include <X11/cursorfont.h> and "window.h". (x_vertical_scrollbar_cursor): New variable. (x_term_init): Initialize it. (last_mouse_bar, last_mouse_bar_frame, last_mouse_part, last_mouse_scroll_range_start, last_mouse_scroll_range_end): New variables. (XTmouse_position): Use them to return scrollbar movement events. Take new arguments, for that purpose. (x_window_to_scrollbar, x_scrollbar_create, x_scrollbar_set_handle, x_scrollbar_remove, x_scrollbar_move, XTset_scrollbar, XTcondemn_scrollbars, XTredeem_scrollbar, XTjudge_scrollbars, x_scrollbar_expose, x_scrollbar_background_expose, x_scrollbar_handle_click, x_scrollbar_handle_motion): New functions to implement scrollbars. (x_term_init): Set the termhooks.h hooks to point to them. (x_set_window_size): Use new macros to calculate frame size. Set vertical_scrollbar_extra field. (x_make_frame_visible): Use the frame accessor FRAME_HAS_VERTICAL_SCROLLBARS to decide if we need to map the frame's subwindows as well. (XTread_socket): Use new size-calculation macros from xterm.h when processing ConfigureNotify events. (x_wm_set_size_hint): Use PIXEL_TO_CHAR_WIDTH and PIXEL_TO_CHAR_HEIGHT macros. * ymakefile (xdisp.o): This now depends on termhooks.h. (xterm.o): This now depends on window.h. * xterm.h (struct x_display): Delete v_scrollbar, v_thumbup, v_thumbdown, v_slider, h_scrollbar, h_thumbup, h_thumbdown, h_slider, v_scrollbar_width, h_scrollbar_height fields. * keyboard.c (Qvscrollbar_part, Qvslider_part, Qvthumbup_part, Qvthumbdown_part, Qhscrollbar_part, Qhslider_part, Qhthumbup_part, Qhthumbdown_part, Qscrollbar_click): Deleted; part of an obsolete interface. (head_table): Removed from here as well. (syms_of_keyboard): And here. * keyboard.h: And here. (POSN_SCROLLBAR_BUTTON): Removed. * xscrollbar.h: File removed - no longer necessary. * xfns.c: Don't #include it any more. (Qhorizontal_scroll_bar, Qvertical_scroll_bar): Deleted. (syms_of_xfns): Don't initialize or staticpro them. (gray_bits): Salvaged from xscrollbar.h. (x_window_to_scrollbar): Deleted. (x_set_horizontal_scrollbar): Deleted. (enum x_frame_parm, x_frame_parms): Remove references to x_set_horizontal_scrollbar. (x_set_foreground_color, x_set_background_color, x_set_border_pixel): Remove special code to support scrollbars. (Fx_create_frame): Remove old scrollbar setup code. (install_vertical_scrollbar, install_horizontal_scrollbar, adjust_scrollbars, x_resize_scrollbars): Deleted. * xterm.c (construct_mouse_click): This doesn't need to take care of scrollbar clicks anymore. (XTread_socket): Remove old code to support scrollbars. Call new functions instead for events which occur in scrollbar windows. (XTupdate_end): Remove call to adjust_scrollbars; the main redisplay code takes care of that now. (enum window_type): Deleted. * ymakefile: Note that xfns.o no longer depends on xscrollbar.h. * xterm.h (PIXEL_WIDTH, PIXEL_HEIGHT): Change name of parameter from `s' to `f'; it's a frame pointer.
author Jim Blandy <jimb@redhat.com>
date Thu, 24 Dec 1992 06:23:08 +0000
parents 85adc3a66e22
children 507f64624555
line wrap: on
line source

/* Contributed by Viktor Dukhovni.  */
/*
 * Unexec for Berkeley a.out format + SUNOS shared libraries
 * The unexeced executable contains the __DYNAMIC area from the
 * original text file,  and then the rest of data + bss + malloced area of
 * the current process.  (The __DYNAMIC area is at the top of the process
 * data segment,  we use "data_start" defined externally to mark the start
 * of the "real" data segment.)
 *
 * For programs that want to remap some of the data segment read only
 * a run_time_remap is provided.  This attempts to remap largest area starting
 * and ending on page boundaries between "data_start" and "bndry"
 * For this it to figure out where the text file is located.  A path search
 * is attempted after trying argv[0] and if all fails we simply do not remap
 *
 * One feature of run_time_remap () is mandatory:  reseting the break.
 *
 *  Note that we can no longer map data into the text segment,  as this causes
 *  the __DYNAMIC struct to become read only,  breaking the runtime loader.
 *  Thus we no longer need to mess with a private crt0.c,  the standard one
 *  will do just fine,  since environ can live in the writable area between
 *  __DYNAMIC and data_start,  just make sure that pre-crt0.o (the name
 *  is somewhat abused here) is loaded first!
 *
 */
#ifdef emacs
#include "config.h"
#endif

#include <sys/param.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include <a.out.h>

/*
 * for programs other than emacs
 * define data_start + initialized here,  and make sure
 * this object is loaded first!
 * emacs will define these elsewhere,  and load the object containing
 * data_start (pre-crt0.o or firstfile.o?) first!
 * The custom crt0.o *must not* be loaded!
 */
#ifndef emacs
  static int data_start = 0;
  static int initialized = 0;
#else
  extern int initialized;
  extern unsigned data_start;
  extern int pureptr;
#endif

extern char *getenv ();
static unsigned Brk;
static struct exec nhdr;
static int rd_only_len;
static long cookie;


unexec (new_name, a_name, bndry, bss_start, entry) 
     char *new_name, *a_name;
     unsigned bndry, bss_start, entry;
{
  char buf[PAGSIZ];
  int fd, new;
  char *old;
  struct exec ohdr;		/* Allocate on the stack,  not needed in the next life */
  struct stat stat;

#ifdef emacs
  fprintf (stderr, "Used %d bytes of Pure Storage\n", pureptr);
#endif

  if ((fd = open (a_name, O_RDONLY)) < 0)
    {
      fprintf (stderr, "%s: open: ", a_name);
      perror (a_name);
      exit (1);
    }
  if ((new = open (new_name, O_WRONLY | O_CREAT, 0666)) == -1)
    {
      fprintf (stderr, "%s: open: ", a_name);
      perror (new_name);
      exit (1);
    }

  if ((fstat (fd, &stat) == -1))
    {
      fprintf (stderr, "%s: ", a_name);
      perror ("fstat");
      exit (1);
    }

  old = (char *)mmap (0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
  if (old == (char *)-1)
    {
      fprintf (stderr, "%s: ", a_name);
      perror ("mmap");
      exit (1);
    }
  close (fd);

  nhdr = ohdr = (*(struct exec *)old);


  /*
   * Remeber a magic cookie so we know we've got the right binary
   * when remaping.
   */
  cookie = time (0);

  Brk = sbrk (0);		/* Save the break, it is reset to &_end (by ld.so?) */

  /*
   * Round up data start to a page boundary (Lose if not a 2 power!)
   */
  data_start = ((((int)&data_start) - 1) & ~(N_PAGSIZ (nhdr) - 1)) + N_PAGSIZ (nhdr);

  /*
   * Round down read only pages to a multiple of the page size
   */
  if (bndry)
    rd_only_len = ((int)bndry & ~(N_PAGSIZ (nhdr) - 1)) - data_start;

#ifndef emacs
  /* Have to do this some time before dumping the data */
  initialized = 1;
#endif
  
  /* 
   * Handle new data and bss sizes and optional new entry point.
   * No one actually uses bss_start and entry,  but tradition compels
   * one to support them.
   * Could complain if bss_start > Brk,  but the caller is *supposed* to know
   * what she is doing.
   */
  nhdr.a_data = (bss_start ? bss_start : Brk) - N_DATADDR (nhdr);
  nhdr.a_bss  = bss_start ? Brk - bss_start : 0;
  if (entry) 
    nhdr.a_entry = entry;

  /*
   * Write out the text segment with new header
   * Dynamic executables are ZMAGIC with N_TXTOFF==0 and the header
   * part of the text segment, but no need to rely on this.
   * So write the TEXT first,  then go back replace the header.
   * Doing it in the other order is less general!
   */
  lseek (new, N_TXTOFF (nhdr), L_SET);
  write (new, old + N_TXTOFF (ohdr), N_TXTOFF (ohdr) + ohdr.a_text);
  lseek (new, 0L, L_SET);
  write (new, &nhdr, sizeof (nhdr));

  /*
   * Write out the head of the old data segment from the file not
   * from core, this has the unresolved __DYNAMIC relocation data
   * we need to reload
   */
  lseek (new, N_DATOFF (nhdr), L_SET);
  write (new, old + N_DATOFF (ohdr), (int)&data_start - N_DATADDR (ohdr));

  /*
   * Copy the rest of the data from core
   */
  write (new, &data_start, N_BSSADDR (nhdr) - (int)&data_start);

  /*
   * Copy the symbol table and line numbers
   */
  lseek (new, N_TRELOFF (nhdr), L_SET);
  write (new, old + N_TRELOFF (ohdr), stat.st_size - N_TRELOFF (ohdr));

  fchmod (new, 0755);
}

void
run_time_remap (progname)
     char *progname;
{
  char aout[MAXPATHLEN];
  register char *path, *p;

  /* Just in case */
  if (!initialized)
    return;

  /* Restore the break */
  brk (Brk);

  /*  If nothing to remap:  we are done! */
  if (rd_only_len == 0)
    return;

  /*
   * Attempt to find the executable
   * First try argv[0],  will almost always succeed as shells tend to give
   * the full path from the hash list rather than using execvp ()
   */
  if (is_it (progname)) 
    return;

  /*
   * If argv[0] is a full path and does not exist,  not much sense in
   * searching further
   */
  if (strchr (progname, '/')) 
    return;

  /*
   * Try to search for  argv[0] on the PATH
   */
  path = getenv ("PATH");
  if (path == NULL)
    return;

  while (*path)
    {
      /* copy through ':' or end */
      for (p = aout; *p = *path; ++p, ++path)
	if (*p == ':')
	  {
	    ++path;		/* move past ':' */
	    break;
	  }
      *p++ = '/';
      strcpy (p, progname);
      /*
       * aout is a candidate full path name
       */
      if (is_it (aout))
	return;
    }
}

is_it (path)
  char *path;
{
  int fd;
  long paths_cookie;
  struct exec hdr;

  /*
   * Open an executable  and check for a valid header!
   * Can't bcmp() the header with what we had,  it may have been stripped!
   * so we may save looking at non executables with the same name, mostly
   * directories.
   */
  fd = open (path, O_RDONLY);
  if (fd != -1)
    {
      if (read (fd, &hdr, sizeof (hdr)) == sizeof (hdr)
	  && !N_BADMAG (hdr) && N_DATOFF (hdr) == N_DATOFF (nhdr)
	  && N_TRELOFF (hdr) == N_TRELOFF (nhdr))
	{
	  /* compare cookies */
	  lseek (fd, N_DATOFF (hdr) + (int)&cookie - N_DATADDR (hdr), L_SET);
	  read (fd, &paths_cookie, sizeof (paths_cookie));
	  if (paths_cookie == cookie)
	    {			/* Eureka */

	      /*
	       * Do the mapping
	       * The PROT_EXEC may not be needed,  but it is safer this way.
	       * should the shared library decide to indirect through
	       * addresses in the data segment not part of __DYNAMIC
	       */
	      mmap (data_start, rd_only_len, PROT_READ | PROT_EXEC,
		    MAP_SHARED | MAP_FIXED, fd,
		    N_DATOFF (hdr) + data_start - N_DATADDR (hdr));
	      close (fd);
	      return 1;
	    }
	}
      close (fd);
    }
  return 0;
}