diff options
Diffstat (limited to 'frontend')
| -rw-r--r-- | frontend/.gitignore | 4 | ||||
| -rw-r--r-- | frontend/Makefile.am | 19 | ||||
| -rw-r--r-- | frontend/jpegtopdf.c | 2 | ||||
| -rw-r--r-- | frontend/saned.c | 361 | ||||
| -rw-r--r-- | frontend/saned.socket | 10 | ||||
| -rw-r--r-- | frontend/saned.xinetd.conf.in | 13 | ||||
| -rw-r--r-- | frontend/saned@.service.in | 11 | ||||
| -rw-r--r-- | frontend/scanimage.c | 201 | 
8 files changed, 359 insertions, 262 deletions
| diff --git a/frontend/.gitignore b/frontend/.gitignore index 90f73a9..e42f6b0 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,2 +1,6 @@  saned +saned@.service +saned.xinetd.conf  scanimage +test +tstbackend diff --git a/frontend/Makefile.am b/frontend/Makefile.am index 9b92645..8573aba 100644 --- a/frontend/Makefile.am +++ b/frontend/Makefile.am @@ -44,5 +44,20 @@ tstbackend_LDADD += -lstdc++  endif  endif -clean-local: -	rm -f test tstbackend +BUILT_SOURCES = saned@.service saned.xinetd.conf + +EXTRA_DIST = saned.socket saned@.service.in saned.xinetd.conf.in + +CLEANFILES = $(EXTRA_PROGRAMS) $(BUILT_SOURCES) + +SUFFIXES = .in +.in: +	$(AM_V_GEN) +	@if $(AM_V_P); then echo Generating $@ from $^; fi +	@sed -e 's|@DATADIR@|$(datadir)|g' \ +	     -e 's|@CONFIGDIR@|$(configdir)|g' \ +	     -e 's|@DOCDIR@|$(docdir)|g' \ +	     -e 's|@LIBDIR@|$(libdir)/sane|g' \ +	     -e 's|@BINDIR@|$(bindir)|g' \ +	     -e 's|@SBINDIR@|$(sbindir)|g' \ +	     -e 's|@PACKAGEVERSION@|$(PACKAGE_VERSION)|g' $? > $@ diff --git a/frontend/jpegtopdf.c b/frontend/jpegtopdf.c index 5c5d712..309411c 100644 --- a/frontend/jpegtopdf.c +++ b/frontend/jpegtopdf.c @@ -91,7 +91,7 @@  #define SANE_PDF_LENGTH_OBJ "%d 0 obj\n%d\nendobj\n"  /* end of stream/object */ -#define SANE_PDF_END_ST_OBJ "endstream\nendobj\n" +#define SANE_PDF_END_ST_OBJ "\nendstream\nendobj\n"  /* object id of first page */ diff --git a/frontend/saned.c b/frontend/saned.c index e31758a..d71d428 100644 --- a/frontend/saned.c +++ b/frontend/saned.c @@ -53,6 +53,7 @@  #include <signal.h>  #include <stdio.h>  #include <stdlib.h> +#include <stdint.h>  #include <string.h>  #include <syslog.h>  #include <time.h> @@ -257,6 +258,7 @@ static int data_connect_timeout = 4000;  static Handle *handle;  static char *bind_addr;  static short bind_port = -1; +static size_t buffer_size = (1 * 1024 * 1024);  static union  {    int w; @@ -1651,168 +1653,186 @@ store_reclen (SANE_Byte * buf, size_t buf_size, int i, size_t reclen)  static void  do_scan (Wire * w, int h, int data_fd)  { -  int num_fds, be_fd = -1, reader, writer, bytes_in_buf, status_dirty = 0; +  int num_fds, be_fd = -1, reader, bytes_in_buf, status_dirty = 0; +  size_t writer;    SANE_Handle be_handle = handle[h].handle;    struct timeval tv, *timeout = 0;    fd_set rd_set, rd_mask, wr_set, wr_mask; -  SANE_Byte buf[8192]; +  SANE_Byte *buf = NULL;    SANE_Status status; -  long int nwritten; +  ssize_t nwritten;    SANE_Int length;    size_t nbytes;    DBG (3, "do_scan: start\n"); -  FD_ZERO (&rd_mask); -  FD_SET (w->io.fd, &rd_mask); -  num_fds = w->io.fd + 1; - -  FD_ZERO (&wr_mask); -  FD_SET (data_fd, &wr_mask); -  if (data_fd >= num_fds) -    num_fds = data_fd + 1; - -  sane_set_io_mode (be_handle, SANE_TRUE); -  if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD) +  /* +   * Allocate the read buffer. +   * +   */ +  buf = malloc (buffer_size); +  if (!buf)      { -      FD_SET (be_fd, &rd_mask); -      if (be_fd >= num_fds) -	num_fds = be_fd + 1; +      status = SANE_STATUS_NO_MEM; +      DBG (DBG_ERR, "do_scan: failed to allocate read buffer (%zu bytes)\n", +           buffer_size);      }    else      { -      memset (&tv, 0, sizeof (tv)); -      timeout = &tv; -    } +      FD_ZERO(&rd_mask); +      FD_SET(w->io.fd, &rd_mask); +      num_fds = w->io.fd + 1; -  status = SANE_STATUS_GOOD; -  reader = writer = bytes_in_buf = 0; -  do -    { -      rd_set = rd_mask; -      wr_set = wr_mask; -      if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0) -	{ -	  if (be_fd >= 0 && errno == EBADF) -	    { -	      /* This normally happens when a backend closes a select -		 filedescriptor when reaching the end of file.  So -		 pass back this status to the client: */ -	      FD_CLR (be_fd, &rd_mask); -	      be_fd = -1; -	      /* only set status_dirty if EOF hasn't been already detected */ -	      if (status == SANE_STATUS_GOOD) -		status_dirty = 1; -	      status = SANE_STATUS_EOF; -	      DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n"); -	      continue; -	    } -	  else -	    { -	      status = SANE_STATUS_IO_ERROR; -	      DBG (DBG_ERR, "do_scan: select failed (%s)\n", strerror (errno)); -	      break; -	    } -	} +      FD_ZERO(&wr_mask); +      FD_SET(data_fd, &wr_mask); +      if (data_fd >= num_fds) +        num_fds = data_fd + 1; -      if (bytes_in_buf) -	{ -	  if (FD_ISSET (data_fd, &wr_set)) -	    { -	      if (bytes_in_buf > 0) -		{ -		  /* write more input data */ -		  nbytes = bytes_in_buf; -		  if (writer + nbytes > sizeof (buf)) -		    nbytes = sizeof (buf) - writer; -		  DBG (DBG_INFO, -		       "do_scan: trying to write %d bytes to client\n", -		       nbytes); -		  nwritten = write (data_fd, buf + writer, nbytes); -		  DBG (DBG_INFO, -		       "do_scan: wrote %ld bytes to client\n", nwritten); -		  if (nwritten < 0) -		    { -		      DBG (DBG_ERR, "do_scan: write failed (%s)\n", -			   strerror (errno)); -		      status = SANE_STATUS_CANCELLED; -	              handle[h].docancel = 1; -		      break; -		    } -		  bytes_in_buf -= nwritten; -		  writer += nwritten; -		  if (writer == sizeof (buf)) -		    writer = 0; -		} -	    } -	} -      else if (status == SANE_STATUS_GOOD -	       && (timeout || FD_ISSET (be_fd, &rd_set))) -	{ -	  int i; +      sane_set_io_mode (be_handle, SANE_TRUE); +      if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD) +        { +          FD_SET(be_fd, &rd_mask); +          if (be_fd >= num_fds) +            num_fds = be_fd + 1; +        } +      else +        { +          memset (&tv, 0, sizeof(tv)); +          timeout = &tv; +        } -	  /* get more input data */ +      status = SANE_STATUS_GOOD; +      reader = writer = bytes_in_buf = 0; +      do +        { +          rd_set = rd_mask; +          wr_set = wr_mask; +          if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0) +            { +              if (be_fd >= 0 && errno == EBADF) +                { +                  /* This normally happens when a backend closes a select +                   filedescriptor when reaching the end of file.  So +                   pass back this status to the client: */ +                  FD_CLR(be_fd, &rd_mask); +                  be_fd = -1; +                  /* only set status_dirty if EOF hasn't been already detected */ +                  if (status == SANE_STATUS_GOOD) +                    status_dirty = 1; +                  status = SANE_STATUS_EOF; +                  DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n"); +                  continue; +                } +              else +                { +                  status = SANE_STATUS_IO_ERROR; +                  DBG (DBG_ERR, "do_scan: select failed (%s)\n", +                       strerror (errno)); +                  break; +                } +            } -	  /* reserve 4 bytes to store the length of the data record: */ -	  i = reader; -	  reader += 4; -	  if (reader >= (int) sizeof (buf)) -	    reader -= sizeof(buf); +          if (bytes_in_buf) +            { +              if (FD_ISSET(data_fd, &wr_set)) +                { +                  if (bytes_in_buf > 0) +                    { +                      /* write more input data */ +                      nbytes = bytes_in_buf; +                      if (writer + nbytes > buffer_size) +                        nbytes = buffer_size - writer; +                      DBG (DBG_INFO, +                           "do_scan: trying to write %d bytes to client\n", +                           nbytes); +                      nwritten = write (data_fd, buf + writer, nbytes); +                      DBG (DBG_INFO, "do_scan: wrote %ld bytes to client\n", +                           nwritten); +                      if (nwritten < 0) +                        { +                          DBG (DBG_ERR, "do_scan: write failed (%s)\n", +                               strerror (errno)); +                          status = SANE_STATUS_CANCELLED; +                          handle[h].docancel = 1; +                          break; +                        } +                      bytes_in_buf -= (size_t) nwritten; +                      writer += (size_t) nwritten; +                      if (writer == buffer_size) +                        writer = 0; +                    } +                } +            } +          else if (status == SANE_STATUS_GOOD +              && (timeout || FD_ISSET(be_fd, &rd_set))) +            { +              int i; -	  assert (bytes_in_buf == 0); -	  nbytes = sizeof (buf) - 4; -	  if (reader + nbytes > sizeof (buf)) -	    nbytes = sizeof (buf) - reader; +              /* get more input data */ -	  DBG (DBG_INFO, -	       "do_scan: trying to read %d bytes from scanner\n", nbytes); -	  status = sane_read (be_handle, buf + reader, nbytes, &length); -	  DBG (DBG_INFO, -	       "do_scan: read %d bytes from scanner\n", length); +              /* reserve 4 bytes to store the length of the data record: */ +              i = reader; +              reader += 4; +              if (reader >= (int) buffer_size) +                reader -= buffer_size; -	  reset_watchdog (); +              assert(bytes_in_buf == 0); +              nbytes = buffer_size - 4; +              if (reader + nbytes > buffer_size) +                nbytes = buffer_size - reader; -	  reader += length; -	  if (reader >= (int) sizeof (buf)) -	    reader = 0; -	  bytes_in_buf += length + 4; +              DBG (DBG_INFO, "do_scan: trying to read %d bytes from scanner\n", +                   nbytes); +              status = sane_read (be_handle, buf + reader, nbytes, &length); +              DBG (DBG_INFO, "do_scan: read %d bytes from scanner\n", length); -	  if (status != SANE_STATUS_GOOD) -	    { -	      reader = i;	/* restore reader index */ -	      status_dirty = 1; -	      DBG (DBG_MSG, -		   "do_scan: status = `%s'\n", sane_strstatus(status)); -	    } -	  else -	    store_reclen (buf, sizeof (buf), i, length); -	} +              reset_watchdog (); -      if (status_dirty && sizeof (buf) - bytes_in_buf >= 5) -	{ -	  status_dirty = 0; -	  reader = store_reclen (buf, sizeof (buf), reader, 0xffffffff); -	  buf[reader] = status; -	  bytes_in_buf += 5; -	  DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n", -	       sane_strstatus(status)); -	} +              reader += length; +              if (reader >= (int) buffer_size) +                reader = 0; +              bytes_in_buf += length + 4; -      if (FD_ISSET (w->io.fd, &rd_set)) -	{ -	  DBG (DBG_MSG, -	       "do_scan: processing RPC request on fd %d\n", w->io.fd); -	  if(process_request (w) < 0) -	    handle[h].docancel = 1; +              if (status != SANE_STATUS_GOOD) +                { +                  reader = i; /* restore reader index */ +                  status_dirty = 1; +                  DBG (DBG_MSG, "do_scan: status = `%s'\n", +                       sane_strstatus (status)); +                } +              else +                store_reclen (buf, buffer_size, i, length); +            } -	  if (handle[h].docancel) -	    break; -	} +          if (status_dirty && buffer_size - bytes_in_buf >= 5) +            { +              status_dirty = 0; +              reader = store_reclen (buf, buffer_size, reader, 0xffffffff); +              buf[reader] = status; +              bytes_in_buf += 5; +              DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n", +                   sane_strstatus (status)); +            } + +          if (FD_ISSET(w->io.fd, &rd_set)) +            { +              DBG (DBG_MSG, "do_scan: processing RPC request on fd %d\n", +                   w->io.fd); +              if (process_request (w) < 0) +                handle[h].docancel = 1; + +              if (handle[h].docancel) +                break; +            } +        } +      while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty); +      DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status)); + +      free (buf); +      buf = NULL;      } -  while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty); -  DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status)); -  if(handle[h].docancel) +  if (handle[h].docancel)      sane_cancel (handle[h].handle);    handle[h].docancel = 0; @@ -2236,8 +2256,8 @@ process_request (Wire * w)  		     strerror (errno));  		return 1;  	      } -	    fcntl (data_fd, F_SETFL, 1);      /* set non-blocking */ -	    shutdown (data_fd, 0); +	    fcntl (data_fd, F_SETFL, O_NONBLOCK);      /* set non-blocking */ +	    shutdown (data_fd, SHUT_RD);  	    do_scan (w, h, data_fd);  	    close (data_fd);  	  } @@ -3413,16 +3433,17 @@ static void usage(char *me, int err)    fprintf (stderr,         "Usage: %s [OPTIONS]\n\n"         " Options:\n\n" -       "  -a, --alone[=user]	equal to `-l -D -u user'\n" -       "  -l, --listen		run in standalone mode (listen for connection)\n" -       "  -u, --user=user	run as `user'\n" -       "  -D, --daemonize	run in background\n" -       "  -o, --once		exit after first client disconnects\n" -       "  -d, --debug=level	set debug level `level' (default is 2)\n" -       "  -e, --stderr		output to stderr\n" -       "  -b, --bind=addr	bind address `addr' (default all interfaces)\n" -       "  -p, --port=port	bind port `port` (default sane-port or 6566)\n" -       "  -h, --help		show this help message and exit\n", me); +       "  -a, --alone[=user]	        equal to `-l -D -u user'\n" +       "  -l, --listen		        run in standalone mode (listen for connection)\n" +       "  -u, --user=user	        run as `user'\n" +       "  -D, --daemonize	        run in background\n" +       "  -o, --once		        exit after first client disconnects\n" +       "  -d, --debug=level	        set debug level `level' (default is 2)\n" +       "  -e, --stderr		        output to stderr\n" +       "  -b, --bind=addr	        bind address `addr' (default all interfaces)\n" +       "  -p, --port=port               bind port `port` (default sane-port or 6566)\n" +       "  -B, --buffer-size=size        set size of read buffer in KB (default: 1024)\n" +       "  -h, --help		        show this help message and exit\n", me);    exit(err);  } @@ -3432,17 +3453,18 @@ static int debug;  static struct option long_options[] =  {  /* These options set a flag. */ -  {"help",	no_argument,		0, 'h'}, -  {"alone",	optional_argument,	0, 'a'}, -  {"listen",	no_argument,		0, 'l'}, -  {"user",	required_argument,	0, 'u'}, -  {"daemonize", no_argument,		0, 'D'}, -  {"once",	no_argument,		0, 'o'}, -  {"debug",	required_argument,	0, 'd'}, -  {"stderr",	no_argument,		0, 'e'}, -  {"bind",	required_argument,	0, 'b'}, -  {"port",	required_argument,	0, 'p'}, -  {0,		0,			0,  0 } +  {"help",              no_argument,            0, 'h'}, +  {"alone",             optional_argument,      0, 'a'}, +  {"listen",            no_argument,            0, 'l'}, +  {"user",              required_argument,      0, 'u'}, +  {"daemonize",         no_argument,            0, 'D'}, +  {"once",              no_argument,            0, 'o'}, +  {"debug",             required_argument,      0, 'd'}, +  {"stderr",            no_argument,            0, 'e'}, +  {"bind",              required_argument,      0, 'b'}, +  {"port",              required_argument,      0, 'p'}, +  {"buffer-size",       required_argument,      0, 'B'}, +  {0,                   0,                      0,  0 }  };  int @@ -3467,7 +3489,7 @@ main (int argc, char *argv[])    run_foreground = SANE_TRUE;    run_once = SANE_FALSE; -  while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:", long_options, &long_index )) != -1) +  while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:B:", long_options, &long_index )) != -1)      {        switch(c) {        case 'a': @@ -3498,8 +3520,25 @@ main (int argc, char *argv[])  	bind_addr = optarg;  	break;        case 'p': -	bind_port = atoi(optarg); -	break; +        bind_port = atoi(optarg); +        break; +      case 'B': +        { +          int buffer_arg = atoi(optarg); + +          if ((buffer_arg < 0) || ((size_t)buffer_arg > (SIZE_MAX / 1024))) +            { +              DBG ( +                  DBG_ERR, +                  "saned: specified buffer size in KB is invalid. Default of %zuKB will be substituted.\n", +                  buffer_size / 1024); +            } +          else +            { +              buffer_size = 1024 * (size_t)buffer_arg; +            } +          break; +        }        case 'h':  	usage(argv[0], EXIT_SUCCESS);  	break; diff --git a/frontend/saned.socket b/frontend/saned.socket new file mode 100644 index 0000000..1aa19e7 --- /dev/null +++ b/frontend/saned.socket @@ -0,0 +1,10 @@ +[Unit] +Description=saned incoming socket + +[Socket] +ListenStream=6566 +Accept=yes +MaxConnections=1 + +[Install] +WantedBy=sockets.target diff --git a/frontend/saned.xinetd.conf.in b/frontend/saned.xinetd.conf.in new file mode 100644 index 0000000..3465dee --- /dev/null +++ b/frontend/saned.xinetd.conf.in @@ -0,0 +1,13 @@ +# default: off +# description: The sane server accepts requests +# for network access to a local scanner via the +# network. +service sane-port +{ +   port        = 6566 +   socket_type = stream +   wait        = no +   user        = saned +   group       = saned +   server      = @SBINDIR@/saned +} diff --git a/frontend/saned@.service.in b/frontend/saned@.service.in new file mode 100644 index 0000000..1682109 --- /dev/null +++ b/frontend/saned@.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=Scanner Service +Requires=saned.socket + +[Service] +ExecStart=@SBINDIR@/saned +User=saned +Group=saned + +[Install] +Also=saned.socket diff --git a/frontend/scanimage.c b/frontend/scanimage.c index d79d487..ff53157 100644 --- a/frontend/scanimage.c +++ b/frontend/scanimage.c @@ -39,15 +39,8 @@  #include <string.h>  #include <unistd.h>  #include <stdarg.h> - -#ifdef __FreeBSD__ -#include <libgen.h> -#endif - -#if defined (__APPLE__) && defined (__MACH__) +#include <errno.h>  #include <libgen.h>     // for basename() -#endif -  #include <sys/types.h>  #include <sys/stat.h> @@ -111,7 +104,7 @@ static struct option basic_options[] = {    {"test", no_argument, NULL, 'T'},    {"all-options", no_argument, NULL, 'A'},    {"version", no_argument, NULL, 'V'}, -  {"buffer-size", optional_argument, NULL, 'B'}, +  {"buffer-size", required_argument, NULL, 'B'},    {"batch", optional_argument, NULL, 'b'},    {"batch-count", required_argument, NULL, OPTION_BATCH_COUNT},    {"batch-start", required_argument, NULL, OPTION_BATCH_START_AT}, @@ -133,29 +126,30 @@ static struct option basic_options[] = {  #define OUTPUT_JPEG     4  #define OUTPUT_PDF      5 -#define BASE_OPTSTRING	"d:hi:Lf:o:B::nvVTAbp" +#define BASE_OPTSTRING	"d:hi:Lf:o:B:nvVTAbp"  #define STRIP_HEIGHT	256	/* # lines we increment image height */ -static struct option *all_options; -static int option_number_len; -static int *option_number; -static SANE_Handle device; -static int verbose; +static struct option *all_options = NULL; +static int option_number_len = 0; +static int *option_number = 0; +static SANE_Handle device = 0; +static int verbose = 0;  static int progress = 0;  static const char* output_file = NULL; -static int test; -static int all; +static int test = 0; +static int all = 0;  static int output_format = OUTPUT_UNKNOWN; -static int help; +static int help = 0;  static int dont_scan = 0; -static const char *prog_name; +static const char *prog_name = NULL;  static int resolution_optind = -1, resolution_value = 0;  /* window (area) related options */ -static SANE_Option_Descriptor window_option[4]; /*updated descs for x,y,l,t*/ -static int window[4]; /*index into backend options for x,y,l,t*/ -static SANE_Word window_val[2]; /*the value for x,y options*/ -static int window_val_user[2];	/* is x,y user-specified? */ +static SANE_Option_Descriptor window_option[4] = {0}; /*updated descs for x,y,l,t*/ +static int window[4] = {0}; /*index into backend options for x,y,l,t*/ +static SANE_Word window_val[2] = {0}; /*the value for x,y options*/ +static int window_val_user[2] = {0};	/* is x,y user-specified? */ +static char *full_optstring = NULL;  static int accept_only_md5_auth = 0;  static const char *icc_profile = NULL; @@ -167,18 +161,16 @@ static SANE_Word tl_x = 0;  static SANE_Word tl_y = 0;  static SANE_Word br_x = 0;  static SANE_Word br_y = 0; -static SANE_Byte *buffer; -static size_t buffer_size; +static SANE_Byte *buffer = NULL; +static size_t buffer_size = 0;  static void  auth_callback (SANE_String_Const resource,  	       SANE_Char * username, SANE_Char * password)  { -  char tmp[3 + 128 + SANE_MAX_USERNAME_LEN + SANE_MAX_PASSWORD_LEN], *wipe; -  unsigned char md5digest[16]; +  char tmp[3 + 128 + SANE_MAX_USERNAME_LEN + SANE_MAX_PASSWORD_LEN];    int md5mode = 0, len, query_user = 1; -  FILE *pass_file;    struct stat stat_buf;    char * uname = NULL; @@ -202,6 +194,7 @@ auth_callback (SANE_String_Const resource,  	}        else  	{ +          FILE *pass_file;  	  if ((pass_file = fopen (tmp, "r")) != NULL)  	    { @@ -291,6 +284,7 @@ auth_callback (SANE_String_Const resource,    if (query_user == 1)      {  #ifdef HAVE_GETPASS +      char *wipe;        strcpy (password, (wipe = getpass ("Enter password: ")));        memset (wipe, 0, strlen (password));  #else @@ -300,6 +294,7 @@ auth_callback (SANE_String_Const resource,    if (md5mode)      { +      unsigned char md5digest[16];        sprintf (tmp, "%.128s%.*s", (strstr (resource, "$MD5$")) + 5,  	       SANE_MAX_PASSWORD_LEN - 1, password); @@ -323,10 +318,10 @@ auth_callback (SANE_String_Const resource,  static void  sighandler (int signum)  { -  static SANE_Bool first_time = SANE_TRUE; -    if (device)      { +      static SANE_Bool first_time = SANE_TRUE; +        fprintf (stderr, "%s: received signal %d\n", prog_name, signum);        if (first_time)  	{ @@ -1210,18 +1205,17 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi,    /* There are nominally 39.3700787401575 inches in a meter. */    const double pixels_per_meter = dpi * 39.3700787401575;    size_t icc_size = 0; -  void *icc_buffer;    *png_ptr = png_create_write_struct         (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);    if (!*png_ptr) {      fprintf(stderr, "png_create_write_struct failed\n"); -    exit(1); +    scanimage_exit (1);    }    *info_ptr = png_create_info_struct(*png_ptr);    if (!*info_ptr) {      fprintf(stderr, "png_create_info_struct failed\n"); -    exit(1); +    scanimage_exit (1);    }    png_init_io(*png_ptr, ofp); @@ -1249,7 +1243,7 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi,    if (icc_profile)      { -      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size); +      void *icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);        if (icc_size > 0)          {  	  /* libpng will abort if the profile and image colour spaces do not match*/ @@ -1260,7 +1254,21 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi,  	  if ((is_gray_profile && color_type == PNG_COLOR_TYPE_GRAY) ||  	      (is_rgb_profile && color_type == PNG_COLOR_TYPE_RGB))  	    { -	      png_set_iCCP(*png_ptr, *info_ptr, basename(icc_profile), PNG_COMPRESSION_TYPE_BASE, icc_buffer, icc_size); +	      char *icc_profile_cp = strdup(icc_profile); +	      if (icc_profile_cp == NULL) +	        { +                  fprintf(stderr, "Memory allocation failure prevented the setting of PNG ICC profile.\n"); +	        } +	      else +	        { +                  png_set_iCCP (*png_ptr, +                                *info_ptr, +                                basename (icc_profile_cp), +                                PNG_COMPRESSION_TYPE_BASE, +                                icc_buffer, +                                icc_size); +                  free(icc_profile_cp); +	        }  	    }  	  else  	    { @@ -1625,11 +1633,11 @@ scan_it (FILE *ofp, void* pw)  #ifdef HAVE_LIBPNG  	      if (output_format == OUTPUT_PNG)  	        { -		  int i = 0; +		  int idx = 0;  		  int left = len;  		  while(pngrow + left >= parm.bytes_per_line)  		    { -		      memcpy(pngbuf + pngrow, buffer + i, parm.bytes_per_line - pngrow); +		      memcpy(pngbuf + pngrow, buffer + idx, parm.bytes_per_line - pngrow);  		      if(parm.depth == 1)  			{  			  int j; @@ -1652,11 +1660,11 @@ scan_it (FILE *ofp, void* pw)                          }  #endif  		      png_write_row(png_ptr, pngbuf); -		      i += parm.bytes_per_line - pngrow; +		      idx += parm.bytes_per_line - pngrow;  		      left -= parm.bytes_per_line - pngrow;  		      pngrow = 0;  		    } -		  memcpy(pngbuf + pngrow, buffer + i, left); +		  memcpy(pngbuf + pngrow, buffer + idx, left);  		  pngrow += left;  		}  	      else @@ -1664,28 +1672,28 @@ scan_it (FILE *ofp, void* pw)  #ifdef HAVE_LIBJPEG  	      if (output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF)  	        { -		  int i = 0; +		  int idx = 0;  		  int left = len;  		  while(jpegrow + left >= parm.bytes_per_line)  		    { -		      memcpy(jpegbuf + jpegrow, buffer + i, parm.bytes_per_line - jpegrow); +		      memcpy(jpegbuf + jpegrow, buffer + idx, parm.bytes_per_line - jpegrow);  		      if(parm.depth == 1)  			{  			  int col1, col8;  			  JSAMPLE *buf8 = malloc(parm.bytes_per_line * 8);  			  for(col1 = 0; col1 < parm.bytes_per_line; col1++)  			    for(col8 = 0; col8 < 8; col8++) -			      buf8[col1 * 8 + col8] = jpegbuf[col1] & (1 << (8 - col8 - 1)) ? 0 : 0xff; +			      buf8[col1 * 8 + col8] = (jpegbuf[col1] & (1 << (8 - col8 - 1))) ? 0 : 0xff;  		          jpeg_write_scanlines(&cinfo, &buf8, 1);  			  free(buf8);  			} else {  		          jpeg_write_scanlines(&cinfo, &jpegbuf, 1);  			} -		      i += parm.bytes_per_line - jpegrow; +		      idx += parm.bytes_per_line - jpegrow;  		      left -= parm.bytes_per_line - jpegrow;  		      jpegrow = 0;  		    } -		  memcpy(jpegbuf + jpegrow, buffer + i, left); +		  memcpy(jpegbuf + jpegrow, buffer + idx, left);  		  jpegrow += left;  		}  	      else @@ -1695,7 +1703,7 @@ scan_it (FILE *ofp, void* pw)  	      else  		{  #if !defined(WORDS_BIGENDIAN) -		  int i, start = 0; +		  int start = 0;  		  /* check if we have saved one byte from the last sane_read */  		  if (hang_over > -1) @@ -1709,12 +1717,12 @@ scan_it (FILE *ofp, void* pw)  			}  		    }  		  /* now do the byte-swapping */ -		  for (i = start; i < (len - 1); i += 2) +		  for (int idx = start; idx < (len - 1); idx += 2)  		    {  		      unsigned char LSB; -		      LSB = buffer[i]; -		      buffer[i] = buffer[i + 1]; -		      buffer[i + 1] = LSB; +		      LSB = buffer[idx]; +		      buffer[idx] = buffer[idx + 1]; +		      buffer[idx + 1] = LSB;  		    }  		  /* check if we have an odd number of bytes */  		  if (((len - start) % 2) != 0) @@ -1783,13 +1791,12 @@ scan_it (FILE *ofp, void* pw)        /* FIXME: other bit depths? */        if (output_format != OUTPUT_TIFF && parm.depth == 16)  	{ -	  int i; -	  for (i = 0; i < image.height * image.width; i += 2) +	  for (int idx = 0; idx < image.height * image.width; idx += 2)  	    {  	      unsigned char LSB; -	      LSB = image.data[i]; -	      image.data[i] = image.data[i + 1]; -	      image.data[i + 1] = LSB; +	      LSB = image.data[idx]; +	      image.data[idx] = image.data[idx + 1]; +	      image.data[idx + 1] = LSB;  	    }  	}  #endif @@ -1996,6 +2003,8 @@ scanimage_exit (int status)      fprintf (stderr, "Calling sane_exit\n");    sane_exit (); +  if (full_optstring) +    free(full_optstring);    if (all_options)      free (all_options);    if (option_number) @@ -2013,15 +2022,12 @@ scanimage_exit (int status)   */  static void print_options(SANE_Device * device, SANE_Int num_dev_options, SANE_Bool ro)  { -  int i, j; -  const SANE_Option_Descriptor *opt; - -  for (i = 1; i < num_dev_options; ++i) +  for (int i = 1; i < num_dev_options; ++i)      { -      opt = 0; +      const SANE_Option_Descriptor *opt = 0;        /* scan area uses modified option struct */ -      for (j = 0; j < 4; ++j) +      for (int j = 0; j < 4; ++j)  	if (i == window[j])  	  opt = window_option + j; @@ -2072,36 +2078,31 @@ static int guess_output_format(const char* output_file)          }      } -  // it would be very confusing if user makes a typo in the filename and the output format changes. -  // This is most likely not what the user wanted. -  fprintf(stderr, "Could not guess output format from the given path and no --format given.\n"); -  exit(1); +  return OUTPUT_UNKNOWN;  }  int  main (int argc, char **argv)  { -  int ch, i, index, all_options_len; +  int ch, index;    const SANE_Device **device_list;    SANE_Int num_dev_options = 0;    const char *devname = 0;    const char *defdevname = 0;    const char *format = 0; -  char readbuf[2]; -  char *readbuf2;    int batch = 0;    int batch_print = 0;    int batch_prompt = 0;    int batch_count = BATCH_COUNT_UNLIMITED;    int batch_start_at = 1;    int batch_increment = 1; +  int promptc;    SANE_Status status; -  char *full_optstring;    SANE_Int version_code;    void *pw = NULL;    FILE *ofp = NULL; -  buffer_size = (32 * 1024);	/* default size */ +  buffer_size = (1024 * 1024);	/* default size */    prog_name = strrchr (argv[0], '/');    if (prog_name) @@ -2148,10 +2149,7 @@ main (int argc, char **argv)            output_file = optarg;            break;  	case 'B': -          if (optarg) -	    buffer_size = 1024 * atoi(optarg); -          else -	    buffer_size = (1024 * 1024); +          buffer_size = 1024 * atoi(optarg);  	  break;  	case 'T':  	  test = 1; @@ -2190,7 +2188,7 @@ main (int argc, char **argv)  	      output_format = OUTPUT_PNG;  #else  	      fprintf(stderr, "PNG support not compiled in\n"); -	      exit(1); +	      scanimage_exit (1);  #endif  	    }  	  else if (strcmp (optarg, "jpeg") == 0) @@ -2199,7 +2197,7 @@ main (int argc, char **argv)  	      output_format = OUTPUT_JPEG;  #else  	      fprintf(stderr, "JPEG support not compiled in\n"); -	      exit(1); +	      scanimage_exit (1);  #endif  	    }  	  else if (strcmp (optarg, "pdf") == 0) @@ -2208,7 +2206,7 @@ main (int argc, char **argv)  	      output_format = OUTPUT_PDF;  #else  	      fprintf(stderr, "PDF support not compiled in\n"); -	      exit(1); +	      scanimage_exit (1);  #endif  	    }            else if (strcmp (optarg, "pnm") == 0) @@ -2226,7 +2224,7 @@ main (int argc, char **argv)                fprintf(stderr, ", jpeg");  #endif                fprintf(stderr, ".\n"); -              exit(1); +              scanimage_exit (1);              }  	  break;  	case OPTION_MD5: @@ -2256,14 +2254,14 @@ main (int argc, char **argv)  	      }  	    else  	      { -		int i = 0, int_arg = 0; -		const char *percent, *start; +		int int_arg = 0; +		const char *percent;  		const char *text_arg = 0;  		char ftype; -		for (i = 0; device_list[i]; ++i) +		for (int dev_num = 0; device_list[dev_num]; ++dev_num)  		  { -		    start = optarg; +		    const char *start = optarg;  		    while (*start && (percent = strchr (start, '%')))  		      {  			int start_len = percent - start; @@ -2273,23 +2271,23 @@ main (int argc, char **argv)  			    switch (*percent)  			      {  			      case 'd': -				text_arg = device_list[i]->name; +				text_arg = device_list[dev_num]->name;  				ftype = 's';  				break;  			      case 'v': -				text_arg = device_list[i]->vendor; +				text_arg = device_list[dev_num]->vendor;  				ftype = 's';  				break;  			      case 'm': -				text_arg = device_list[i]->model; +				text_arg = device_list[dev_num]->model;  				ftype = 's';  				break;  			      case 't': -				text_arg = device_list[i]->type; +				text_arg = device_list[dev_num]->type;  				ftype = 's';  				break;  			      case 'i': -				int_arg = i; +				int_arg = dev_num;  				ftype = 'i';  				break;  			      case 'n': @@ -2401,12 +2399,20 @@ Parameters are separated by a blank from single-character options (e.g.\n\    if (batch && output_file != NULL)      {        fprintf(stderr, "--batch and --output-file can't be used together.\n"); -      exit(1); +      scanimage_exit (1);      }    if (output_format == OUTPUT_UNKNOWN) -    output_format = guess_output_format(output_file); - +    { +      output_format = guess_output_format(output_file); +      if (output_format == OUTPUT_UNKNOWN) +        { +          // it would be very confusing if user makes a typo in the filename and the output format changes. +          // This is most likely not what the user wanted. +          fprintf(stderr, "Could not guess output format from the given path and no --format given.\n"); +          scanimage_exit (1); +        } +    }    if (!devname)      {        /* If no device name was specified explicitly, we look at the @@ -2474,7 +2480,7 @@ Parameters are separated by a blank from single-character options (e.g.\n\  	}        /* malloc global option lists */ -      all_options_len = num_dev_options + NELEMS (basic_options) + 1; +      int all_options_len = num_dev_options + NELEMS (basic_options) + 1;        all_options = malloc (all_options_len * sizeof (all_options[0]));        option_number_len = num_dev_options;        option_number = malloc (option_number_len * sizeof (option_number[0])); @@ -2579,6 +2585,7 @@ Parameters are separated by a blank from single-character options (e.g.\n\  	}        free (full_optstring); +      full_optstring = NULL;        /* convert x/y to br_x/br_y */        for (index = 0; index < 2; ++index) @@ -2624,7 +2631,7 @@ List of available devices:", prog_name);  	{  	  int column = 80; -	  for (i = 0; device_list[i]; ++i) +	  for (int i = 0; device_list[i]; ++i)  	    {  	      if (column + strlen (device_list[i]->name) + 1 >= 80)  		{ @@ -2741,21 +2748,19 @@ List of available devices:", prog_name);  	      if (output_format != OUTPUT_PDF)  #endif       	         strcat (part_path, ".part"); -	    } - -	  if (batch) -	    {  	      if (batch_prompt)  		{  		  fprintf (stderr, "Place document no. %d on the scanner.\n",  			   n);  		  fprintf (stderr, "Press <RETURN> to continue.\n"); -		  fprintf (stderr, "Press Ctrl + D to terminate.\n"); -		  readbuf2 = fgets (readbuf, 2, stdin); +		  fprintf (stderr, "Press Ctrl + D (EOF) to terminate.\n"); +		  while ((promptc = getchar()) != '\n' && promptc != EOF); -		  if (readbuf2 == NULL) +		  if (promptc == EOF)  		    { +		      if (ferror(stdin)) +			fprintf(stderr, "%s: stdin error: %s\n", prog_name, strerror(errno));  		      if (ofp)  			{  #ifdef HAVE_LIBJPEG | 
