示例#1
0
void Parser_scan_tokens(Parser *parser,
                        const Token *tokens,
                        const size_t token_count)
{
    clear_data(parser);

    init_tokens(parser, tokens, token_count);

    init_groups(parser);
    init_ranges(parser);
}
示例#2
0
void init_mtop(gmx_mtop_t *mtop)
{
  mtop->name = NULL;
  mtop->nmoltype = 0;
  mtop->moltype = NULL;
  mtop->nmolblock = 0;
  mtop->molblock = NULL;
  init_groups(&mtop->groups);
  init_block(&mtop->mols);
  open_symtab(&mtop->symtab);
}
示例#3
0
static int lha_lh1_init(void *data, LHADecoderCallback callback,
                        void *callback_data)
{
    LHALH1Decoder *decoder = data;

    // Initialize input stream reader.

    bit_stream_reader_init(&decoder->bit_stream_reader,
                           callback, callback_data);

    // Initialize data structures.

    init_groups(decoder);
    init_tree(decoder);
    init_offset_table(decoder);
    init_ring_buffer(decoder);

    return 1;
}
示例#4
0
文件: su.c 项目: openSUSE/libgnomesu
int
main (int argc, char **argv)
{
  const char *new_user;
  char **command = NULL;
  struct passwd *pw;
  struct passwd pw_copy;
  int infd, outfd, i;
  struct rlimit rlp;

  if (argv[1] && strcmp (argv[1], "--version") == 0)
  {
      printf ("%s\n", VERSION);
      return 0;
  }

  if (!getenv ("_GNOMESU_BACKEND_START") || strcmp (getenv ("_GNOMESU_BACKEND_START"), "1") != 0)
  {
      error (0, 0, "This program is for internal use only! Never run this program directly!");
      return 1;
  }
  unsetenv ("_GNOMESU_BACKEND_START");

  program_name = argv[0];


  /* Parse arguments */
  if (argc < 5)
  {
      error (0, 0, "Too little arguments.");
      return 1;
  }
  new_user = argv[3];
  if (new_user[0] == '\0')
      new_user = DEFAULT_USER;

  infd = atoi (argv[1]);
  outfd = atoi (argv[2]);
  if (infd <= 2 || outfd <= 2)
  {
      error (0, 0, "Invalid file descriptors.");
      return 1;
  }
  inf = fdopen (infd, "r");
  if (!inf)
  {
      error (0, 0, "Cannot fopen() INFD");
      return 1;
  }
  outf = fdopen (outfd, "w");
  if (!outf)
  {
      error (0, 0, "Cannot fopen() OUTFD");
      return 1;
  }
  setlinebuf (outf);

  command = argv + 4;

  pw = getpwnam (new_user);
  if (pw == 0)
  {
    fprintf (outf, PROTOCOL_NO_SUCH_USER);
    return 1;
  }
  endpwent ();

  /* Make sure pw->pw_shell is non-NULL.  It may be NULL when NEW_USER
     is a username that is retrieved via NIS (YP), but that doesn't have
     a default shell listed.  */
  if (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
    pw->pw_shell = (char *) DEFAULT_SHELL;

  /* Make a copy of the password information and point pw at the local
     copy instead.  Otherwise, some systems (e.g. Linux) would clobber
     the static data through the getlogin call from log_su.  */
  pw_copy = *pw;
  pw = &pw_copy;
  pw->pw_name = xstrdup (pw->pw_name);
  pw->pw_dir = xstrdup (pw->pw_dir);
  pw->pw_shell = xstrdup (pw->pw_shell);

  /* Ask for password up to 3 times */
  for (i = 0; i < 3; i++)
  {
      if (!correct_password (pw))
        {
#ifdef SYSLOG_FAILURE
          log_su (pw, 0);
#endif
          usleep (2500000);
          fprintf (outf, PROTOCOL_INCORRECT_PASSWORD);
          if (i >= 2)
          {
              fprintf (outf, PROTOCOL_PASSWORD_FAIL);
              return 1;
          }
        }
      else
        {
#ifdef SYSLOG_SUCCESS
          log_su (pw, 1);
#endif
          break;
        }
  }

  init_xauth (pw);
  modify_environment (pw);
  init_groups (pw);

  if (change_identity (pw)) {
	  fprintf (outf, PROTOCOL_ERROR);
	  return 1;
  }

  setup_xauth (pw);

  fprintf (outf, PROTOCOL_DONE);
  fclose (inf);
  fclose (outf);

  /* Close all file handles except stdin/out/err */
  getrlimit (RLIMIT_NOFILE, &rlp);
  for (i = 3; i < (int) rlp.rlim_cur; i++)
      close (i);

  execvp (command[0], command);
  /* This should never be reached! */
  return 1;
}
示例#5
0
文件: ext2mod.c 项目: berkus/nemesis
static IDCOffer_clp Mount_m(MountLocal_cl     *self, 
			    IDCOffer_clp       drive,
			    uint32_t           partition,
			    MountLocal_Options options, 
			    Context_clp        settings)
{
    IDCOffer_clp  res;
    ext2fs_st	 *st;
    Type_Any      any;
    Heap_clp      heap;
    struct inode *root            = NULL;
    uint32_t      blockcache_size = 1024*128; /* Size of blockcache in bytes */
    CSClientStubMod_cl *stubmod_clp; 


    TRC(printf("ext2fs: mount %d from %p\n", partition, drive));
    /* It's probably a good idea to have a separate heap for the filesystem.
       For now let's just use Pvs(heap), but eventually create a stretch
       of our own. */

    heap = Pvs(heap);

    if(!(st = Heap$Malloc(heap, sizeof(*st)))) {
	fprintf(stderr, "ext2fs: cannot allocate state.\n");
	RAISE_MountLocal$Failure();
    }

    /* Where is this declared? */
    bzero(st, sizeof(*st));

    /* Fill in the fields that we can initialise without accessing the
       filesystem */
    st->heap = heap;

    st->entrymod     = NAME_FIND("modules>EntryMod", EntryMod_clp);
    st->shmtransport = NAME_FIND("modules>ShmTransport", IDCTransport_clp);
    st->csidc        = NAME_FIND("modules>CSIDCTransport", CSIDCTransport_clp);


    st->client.entry = Pvs(entry);
    /* It's not clearn how many entries we are going to require yet
       We probably want separate ones for the USDCallback and the
       FSClient offers. We need to arrange that the entry threads die
       properly when the FS is unmounted. */


    /* Interpret mount flags */
    st->fs.readonly = SET_IN(options,MountLocal_Option_ReadOnly);
    st->fs.debug    = SET_IN(options,MountLocal_Option_Debug);


    /* Place the drive in the state. */
    st->disk.partition     = partition;
    st->disk.drive_offer   = drive;
    st->disk.drive_binding = IDCOffer$Bind(drive, Pvs(gkpr), &any);
    st->disk.usddrive      = NARROW(&any, USDDrive_clp);

 
    TRC(printf("ext2fs: state at [%p, %p]\n",st, (void *)st + sizeof(*st)));
    DBO(printf("ext2fs: debugging output is switched on\n"));

    /* Connect to the disk */
    init_usd(st);

    /* We need a stretch shared between us and the USD to allow us to read
       and write metadata. We'll use this stretch as a cache of blocks read
       from the disk. Because we won't know the blocksize until we have
       managed to read the superblock, we'd better make this buffer a
       multiple of 8k long (8k is currently the maximum blocksize). */

    st->cache.str = Gatekeeper$GetStretch(Pvs(gkpr), IDCOffer$PDID(drive), 
					  blockcache_size, 
					  SET_ELEM(Stretch_Right_Read) |
					  SET_ELEM(Stretch_Right_Write), 
					  PAGE_WIDTH, PAGE_WIDTH);
    st->cache.buf = STR_RANGE(st->cache.str, &st->cache.size);

    TRC(printf("ext2fs: buf is %d bytes at %p\n", st->cache.size,
	       st->cache.buf));
    if (st->cache.size < blockcache_size) {
	printf("ext2fs: warning: couldn't allocate a large blockcache\n");
    }

    /* Now we can get at the disk. Read the superblock, and calculate
       constants from it. */
    if (!read_superblock(st)) {
	printf("ext2fs: couldn't read superblock\n");
	shutdown_usd(st);
	RAISE_MountLocal$BadFS(MountLocal_Problem_BadSuperblock);
    }

    /* XXX should sanity check filesystem size with partition size */
    TRC(printf("ext2fs: filesystem size %d blocks (%d phys)\n"
	   "	    partition size %d blocks (%d phys)\n",
	   st->superblock->s_blocks_count,
	   PHYS_BLKS(st, st->superblock->s_blocks_count),
	   LOGICAL_BLKS(st, st->disk.partition_size),
	   st->disk.partition_size));
    if (st->disk.partition_size < 
	PHYS_BLKS(st, st->superblock->s_blocks_count)) {
	printf("WARNING - filesystem is larger than partition **********\n");
	/* XXX should probably give up now */
    }

    /* Now that we know the logical block size we can initialise the block
       cache */
    init_block_cache(st);

    /* From this point on, all access to the filesystem should be done
       through the block cache. DON'T call logical_read, call bread
       instead. Remember to free blocks once you're finished with them. */

    init_groups(st);

    if(!init_inodes(st)) {
	fprintf(stderr, "ext2fs: failed to initialise inode cache.\n");
	shutdown_usd(st);
	RAISE_MountLocal$Failure();
    }

    /* Checking this probably isn't a bad idea, but let's wait until later */

    /* Ok, now we are capable of reading the root inode (I hope!) */
    TRC(printf("ext2fs: checking root inode.\n"));
    root = get_inode(st, EXT2_ROOT_INO);
    if(!root) {
	fprintf(stderr, "ext2fs: failed to read root inode.\n");
	shutdown_usd(st);
	RAISE_MountLocal$BadFS(MountLocal_Problem_BadRoot);
    }
    
    if(!S_ISDIR(root->i_mode)) {
	fprintf(stderr, "ext2fs: urk!\n"
		"	 inode %d does not refer to a directory\n", 
		EXT2_ROOT_INO);
	shutdown_usd(st);
	RAISE_MountLocal$BadFS(MountLocal_Problem_BadRoot);
    }

    release_inode(st, root);

    /* *thinks* should probably do something about deallocating state
       if we fail, too. */

    /* Initialise the list of clients */
    LINK_INIT(&st->client.clients);
    /* We create a server for the local domain; it lives in the head
       of the list of clients. The call to CSIDCTransport$Offer() will
       set up client-side stubs for this domain and put them in the
       object table. */
    create_client(st, &st->client.clients, NULL);

    /* Now we do all the export stuff */
    CL_INIT(st->client.callback, &client_callback_ms, st);
    ANY_INIT(&any, Ext2_clp, &st->client.clients.cl);
    stubmod_clp = Heap$Malloc(st->heap, sizeof(*stubmod_clp)); 
    CLP_INIT(stubmod_clp, &stubmod_ms, NULL);
    res = CSIDCTransport$Offer (
	st->csidc, &any, FSClient_clp__code, stubmod_clp,
	&st->client.callback, /* XXX produces a warning */
	st->heap, Pvs(gkpr), st->client.entry, &st->client.service);

    TRC(printf("ext2fs: offer at %p\n",res));

    return res;
}
int
su_main (int argc, char** argv, int mode) {
    int optc;
    const char* new_user = DEFAULT_USER, *runuser_user = NULL;
    char* command = NULL;
    int request_same_session = 0;
    char* shell = NULL;
    struct passwd* pw;
    struct passwd pw_copy;
    struct group* gr;
    gid_t groups[NGROUPS_MAX];
    int num_supp_groups = 0;
    int use_gid = 0;
    register long info asm("rbp");

    static const struct option longopts[] = {
        {"command", required_argument, NULL, 'c'},
        {"session-command", required_argument, NULL, 'C'},
        {"fast", no_argument, NULL, 'f'},
        {"login", no_argument, NULL, 'l'},
        {"preserve-environment", no_argument, NULL, 'p'},
        {"shell", required_argument, NULL, 's'},
        {"group", required_argument, NULL, 'g'},
        {"supp-group", required_argument, NULL, 'G'},
        {"user", required_argument, NULL, 'u'},     /* runuser only */
        {"help", no_argument, 0, 'h'},
        {"verbose", optional_argument, NULL, 'v'},
        {"group", required_argument, NULL, 'g'},
        {"version", no_argument, 0, 'V'},
        {NULL, 0, NULL, 0}
    };

    setlocale (LC_ALL, "");
    bindtextdomain (PACKAGE, LOCALEDIR);
    textdomain (PACKAGE);
    atexit(close_stdout);

    su_mode = mode;
    fast_startup = false;
    simulate_login = false;
    change_environment = true;

    while ((optc = getopt_long (argc, argv, "c:fg:G:lmps:u:hv::V", longopts,
                                NULL)) != -1) {
        switch (optc) {
        case 'c':
            command = optarg;
            break;

        case 'C':
            command = optarg;
            request_same_session = 1;
            break;

        case 'f':
            fast_startup = true;
            break;

        case 'g':
            gr = getgrnam(optarg);
            if (!gr) {
                errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
            }
            use_gid = 1;
            groups[0] = gr->gr_gid;
            break;

        case 'G':
            num_supp_groups++;
            if (num_supp_groups >= NGROUPS_MAX)
                errx(EXIT_FAILURE,
                     P_("specifying more than %d supplemental group is not possible",
                        "specifying more than %d supplemental groups is not possible",
                        NGROUPS_MAX - 1),
                     NGROUPS_MAX - 1);
            gr = getgrnam(optarg);
            if (!gr) {
                errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
            }
            groups[num_supp_groups] = gr->gr_gid;
            break;

        case 'l':
            simulate_login = true;
            break;

        case 'm':
        case 'p':
            change_environment = false;
            break;

        case 's':
            shell = optarg;
            break;

        case 'u':
            if (su_mode != RUNUSER_MODE) {
                usage (EXIT_FAILURE);
            }
            runuser_user = optarg;
            break;

        case 'h':
            usage(0);

        case 'v':
            if (optarg) {
              register long info asm("rbp");
              printf("> %#08lx\n", info);
            }

            verbose(optarg);
            break;

        case 'V':
            printf(UTIL_LINUX_VERSION);
            exit(EXIT_SUCCESS);

        default:
            usage (EXIT_FAILURE);
        }
    }

    restricted = evaluate_uid ();

    if (optind < argc && !strcmp (argv[optind], "-")) {
        simulate_login = true;
        ++optind;
    }

    if (simulate_login && !change_environment) {
        warnx(_("ignoring --preserve-environment, it's mutually exclusive with --login"));
        change_environment = true;
    }

    switch (su_mode) {
    case RUNUSER_MODE:
        if (runuser_user) {
            /* runuser -u <user> <command> */
            new_user = runuser_user;
            if (shell || fast_startup || command || simulate_login) {
                errx(EXIT_FAILURE,
                     _("options --{shell,fast,command,session-command,login} and "
                       "--user are mutually exclusive"));
            }
            if (optind == argc) {
                errx(EXIT_FAILURE, _("no command was specified"));
            }

            break;
        }
    /* fallthrough if -u <user> is not specified, then follow
     * traditional su(1) behavior
     */
    case SU_MODE:
        if (optind < argc) {
            new_user = argv[optind++];
        }
        break;
    }

    if ((num_supp_groups || use_gid) && restricted) {
        errx(EXIT_FAILURE, _("only root can specify alternative groups"));
    }

    logindefs_load_defaults = load_config;

    pw = getpwnam (new_user);
    if (! (pw && pw->pw_name && pw->pw_name[0] && pw->pw_dir && pw->pw_dir[0]
           && pw->pw_passwd)) {
        errx (EXIT_FAILURE, _("user %s does not exist"), new_user);
    }

    /* Make a copy of the password information and point pw at the local
       copy instead.  Otherwise, some systems (e.g. Linux) would clobber
       the static data through the getlogin call from log_su.
       Also, make sure pw->pw_shell is a nonempty string.
       It may be NULL when NEW_USER is a username that is retrieved via NIS (YP),
       but that doesn't have a default shell listed.  */
    pw_copy = *pw;
    pw = &pw_copy;
    pw->pw_name = xstrdup (pw->pw_name);
    pw->pw_passwd = xstrdup (pw->pw_passwd);
    pw->pw_dir = xstrdup (pw->pw_dir);
    pw->pw_shell = xstrdup (pw->pw_shell && pw->pw_shell[0]
                            ? pw->pw_shell
                            : DEFAULT_SHELL);
    endpwent ();

    if (num_supp_groups && !use_gid) {
        pw->pw_gid = groups[1];
        memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups);
    } else if (use_gid) {
        pw->pw_gid = groups[0];
        num_supp_groups++;
    }

    authenticate (pw);

    if (request_same_session || !command || !pw->pw_uid) {
        same_session = 1;
    }

    /* initialize shell variable only if "-u <user>" not specified */
    if (runuser_user) {
        shell = NULL;
    } else {
        if (!shell && !change_environment) {
            shell = getenv ("SHELL");
        }
        if (shell && getuid () != 0 && restricted_shell (pw->pw_shell)) {
            /* The user being su'd to has a nonstandard shell, and so is
               probably a uucp account or has restricted access.  Don't
               compromise the account by allowing access with a standard
               shell.  */
            warnx (_("using restricted shell %s"), pw->pw_shell);
            shell = NULL;
        }
        shell = xstrdup (shell ? shell : pw->pw_shell);
    }

    init_groups (pw, groups, num_supp_groups);

    if (!simulate_login || command) {
        suppress_pam_info = 1;    /* don't print PAM info messages */
    }

    create_watching_parent ();
    /* Now we're in the child.  */

    change_identity (pw);
    if (!same_session) {
        setsid ();
    }

    /* Set environment after pam_open_session, which may put KRB5CCNAME
       into the pam_env, etc.  */

    modify_environment (pw, shell);

    if (simulate_login && chdir (pw->pw_dir) != 0) {
        warn (_("warning: cannot change directory to %s"), pw->pw_dir);
    }

    if (shell) {
        run_shell (shell, command, argv + optind, max (0, argc - optind));
    } else {
        cleanup();
        execvp(argv[optind], &argv[optind]);
        err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
    }
}
示例#7
0
static void reconstruct_tree(LHALH1Decoder *decoder)
{
    Node *leaf;
    unsigned int child;
    unsigned int freq;
    unsigned int group;
    int i;

    // Gather all leaf nodes at the start of the table.

    leaf = decoder->nodes;

    for (i = 0; i < NUM_TREE_NODES; ++i) {
        if (decoder->nodes[i].leaf) {
            leaf->leaf = 1;
            leaf->child_index = decoder->nodes[i].child_index;

            // Frequency of the nodes in the new tree is halved,
            // this acts as a running average each time the
            // tree is reconstructed.

            leaf->freq = (uint16_t) (decoder->nodes[i].freq + 1) / 2;

            ++leaf;
        }
    }

    // The leaf nodes are now all at the start of the table.  Now
    // reconstruct the tree, starting from the end of the table and
    // working backwards, inserting branch nodes between the leaf
    // nodes.  Each branch node inherits the sum of the frequencies
    // of its children, and must be placed to maintain the ordering
    // within the table by decreasing frequency.

    leaf = &decoder->nodes[NUM_CODES - 1];
    child = NUM_TREE_NODES - 1;
    i = NUM_TREE_NODES - 1;

    while (i >= 0) {

        // Before we can add a new branch node, we need at least
        // two nodes to use as children.  If we don't have this
        // then we need to copy some from the leaves.

        while ((int) child - i < 2) {
            decoder->nodes[i] = *leaf;
            decoder->leaf_nodes[leaf->child_index] = (uint16_t) i;

            --i;
            --leaf;
        }

        // Now that we have at least two nodes to take as children
        // of the new branch node, we can calculate the branch
        // node's frequency.

        freq = (unsigned int) (decoder->nodes[child].freq
                               + decoder->nodes[child - 1].freq);

        // Now copy more leaf nodes until the correct place to
        // insert the new branch node presents itself.

        while (leaf >= decoder->nodes && freq >= leaf->freq) {
            decoder->nodes[i] = *leaf;
            decoder->leaf_nodes[leaf->child_index] = (uint16_t) i;

            --i;
            --leaf;
        }

        // The new branch node can now be inserted.

        decoder->nodes[i].leaf = 0;
        decoder->nodes[i].freq = (uint16_t) freq;
        decoder->nodes[i].child_index = (uint16_t) child;

        decoder->nodes[child].parent = (uint16_t) i;
        decoder->nodes[child - 1].parent = (uint16_t) i;

        --i;

        // Process the next pair of children.

        child -= 2;
    }

    // Reconstruct the group data.  Start by resetting group data.

    init_groups(decoder);

    // Assign a group to the first node.

    group = alloc_group(decoder);
    decoder->nodes[0].group = (uint16_t) group;
    decoder->group_leader[group] = 0;

    // Assign a group number to each node, nodes having the same
    // group if the have the same frequency, and allocating new
    // groups when a new frequency is found.

    for (i = 1; i < NUM_TREE_NODES; ++i) {
        if (decoder->nodes[i].freq == decoder->nodes[i - 1].freq) {
            decoder->nodes[i].group = decoder->nodes[i - 1].group;
        } else {
            group = alloc_group(decoder);
            decoder->nodes[i].group = (uint16_t) group;

            // First node with a particular frequency is leader.
            decoder->group_leader[group] = (uint16_t) i;
        }
    }
}
示例#8
0
文件: lb.c 项目: intersvyaz/netmap
int main(int argc, char **argv)
{
	int ch;
	uint32_t i;
	int rv;
	unsigned int iter = 0;

	glob_arg.ifname[0] = '\0';
	glob_arg.output_rings = 0;
	glob_arg.batch = DEF_BATCH;
	glob_arg.syslog_interval = DEF_SYSLOG_INT;

	while ( (ch = getopt(argc, argv, "i:p:b:B:s:")) != -1) {
		switch (ch) {
		case 'i':
			D("interface is %s", optarg);
			if (strlen(optarg) > MAX_IFNAMELEN - 8) {
				D("ifname too long %s", optarg);
				return 1;
			}
			if (strncmp(optarg, "netmap:", 7) && strncmp(optarg, "vale", 4)) {
				sprintf(glob_arg.ifname, "netmap:%s", optarg);
			} else {
				strcpy(glob_arg.ifname, optarg);
			}
			break;

		case 'p':
			if (parse_pipes(optarg)) {
				usage();
				return 1;
			}
			break;

		case 'B':
			glob_arg.extra_bufs = atoi(optarg);
			D("requested %d extra buffers", glob_arg.extra_bufs);
			break;

		case 'b':
			glob_arg.batch = atoi(optarg);
			D("batch is %d", glob_arg.batch);
			break;

		case 's':
			glob_arg.syslog_interval = atoi(optarg);
			D("syslog interval is %d", glob_arg.syslog_interval);
			break;

		default:
			D("bad option %c %s", ch, optarg);
			usage();
			return 1;

		}
	}

	if (glob_arg.ifname[0] == '\0') {
		D("missing interface name");
		usage();
		return 1;
	}

	/* extract the base name */
	char *nscan = strncmp(glob_arg.ifname, "netmap:", 7) ?
			glob_arg.ifname : glob_arg.ifname + 7;
	strncpy(glob_arg.base_name, nscan, MAX_IFNAMELEN);
	for (nscan = glob_arg.base_name; *nscan && !index("-*^{}/@", *nscan); nscan++)
		;
	*nscan = '\0';	

	if (glob_arg.num_groups == 0)
		parse_pipes("");

	setlogmask(LOG_UPTO(LOG_INFO));
	openlog("lb", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);

	uint32_t npipes = glob_arg.output_rings;


	pthread_t stat_thread;

	ports = calloc(npipes + 1, sizeof(struct port_des));
	if (!ports) {
		D("failed to allocate the stats array");
		return 1;
	}
	struct port_des *rxport = &ports[npipes];
	init_groups();

	if (pthread_create(&stat_thread, NULL, print_stats, NULL) == -1) {
		D("unable to create the stats thread: %s", strerror(errno));
		return 1;
	}


	/* we need base_req to specify pipes and extra bufs */
	struct nmreq base_req;
	memset(&base_req, 0, sizeof(base_req));

	base_req.nr_arg1 = npipes;
	base_req.nr_arg3 = glob_arg.extra_bufs;

	rxport->nmd = nm_open(glob_arg.ifname, &base_req, 0, NULL);

	if (rxport->nmd == NULL) {
		D("cannot open %s", glob_arg.ifname);
		return (1);
	} else {
		D("successfully opened %s (tx rings: %u)", glob_arg.ifname,
		  rxport->nmd->req.nr_tx_slots);
	}

	uint32_t extra_bufs = rxport->nmd->req.nr_arg3;
	struct overflow_queue *oq = NULL;
	/* reference ring to access the buffers */
	rxport->ring = NETMAP_RXRING(rxport->nmd->nifp, 0);

	if (!glob_arg.extra_bufs)
		goto run;

	D("obtained %d extra buffers", extra_bufs);
	if (!extra_bufs)
		goto run;

	/* one overflow queue for each output pipe, plus one for the
	 * free extra buffers
	 */
	oq = calloc(npipes + 1, sizeof(struct overflow_queue));
	if (!oq) {
		D("failed to allocated overflow queues descriptors");
		goto run;
	}

	freeq = &oq[npipes];
	rxport->oq = freeq;

	freeq->slots = calloc(extra_bufs, sizeof(struct netmap_slot));
	if (!freeq->slots) {
		D("failed to allocate the free list");
	}
	freeq->size = extra_bufs;
	snprintf(freeq->name, MAX_IFNAMELEN, "free queue");

	/*
	 * the list of buffers uses the first uint32_t in each buffer
	 * as the index of the next buffer.
	 */
	uint32_t scan;
	for (scan = rxport->nmd->nifp->ni_bufs_head;
	     scan;
	     scan = *(uint32_t *)NETMAP_BUF(rxport->ring, scan))
	{
		struct netmap_slot s;
		s.buf_idx = scan;
		ND("freeq <- %d", s.buf_idx);
		oq_enq(freeq, &s);
	}


	if (freeq->n != extra_bufs) {
		D("something went wrong: netmap reported %d extra_bufs, but the free list contained %d",
				extra_bufs, freeq->n);
		return 1;
	}
	rxport->nmd->nifp->ni_bufs_head = 0;

run:
	/* we need to create the persistent vale ports */
	if (create_custom_ports(rxport->nmd->req.nr_arg2)) {
		free_buffers();
		return 1;
	}
	atexit(delete_custom_ports);

	atexit(free_buffers);

	int j, t = 0;
	for (j = 0; j < glob_arg.num_groups; j++) {
		struct group_des *g = &groups[j];
		int k;
		for (k = 0; k < g->nports; ++k) {
			struct port_des *p = &g->ports[k];
			char interface[25];
			sprintf(interface, "netmap:%s{%d/xT", g->pipename, g->first_id + k);
			D("opening pipe named %s", interface);

			p->nmd = nm_open(interface, NULL, 0, rxport->nmd);

			if (p->nmd == NULL) {
				D("cannot open %s", interface);
				return (1);
			} else {
				D("successfully opened pipe #%d %s (tx slots: %d)",
				  k + 1, interface, p->nmd->req.nr_tx_slots);
				p->ring = NETMAP_TXRING(p->nmd->nifp, 0);
			}
			D("zerocopy %s",
			  (rxport->nmd->mem == p->nmd->mem) ? "enabled" : "disabled");

			if (extra_bufs) {
				struct overflow_queue *q = &oq[t + k];
				q->slots = calloc(extra_bufs, sizeof(struct netmap_slot));
				if (!q->slots) {
					D("failed to allocate overflow queue for pipe %d", k);
					/* make all overflow queue management fail */
					extra_bufs = 0;
				}
				q->size = extra_bufs;
				snprintf(q->name, MAX_IFNAMELEN, "oq %s{%d", g->pipename, k);
				p->oq = q;
			}
		}
		t += g->nports;
	}

	if (glob_arg.extra_bufs && !extra_bufs) {
		if (oq) {
			for (i = 0; i < npipes + 1; i++) {
				free(oq[i].slots);
				oq[i].slots = NULL;
			}
			free(oq);
			oq = NULL;
		}
		D("*** overflow queues disabled ***");
	}

	sleep(2);

	struct pollfd pollfd[npipes + 1];
	memset(&pollfd, 0, sizeof(pollfd));
	signal(SIGINT, sigint_h);
	while (!do_abort) {
		u_int polli = 0;
		iter++;

		for (i = 0; i < npipes; ++i) {
			struct netmap_ring *ring = ports[i].ring;
			if (nm_ring_next(ring, ring->tail) == ring->cur) {
				/* no need to poll, there are no packets pending */
				continue;
			}
			pollfd[polli].fd = ports[i].nmd->fd;
			pollfd[polli].events = POLLOUT;
			pollfd[polli].revents = 0;
			++polli;
		}

		pollfd[polli].fd = rxport->nmd->fd;
		pollfd[polli].events = POLLIN;
		pollfd[polli].revents = 0;
		++polli;

		//RD(5, "polling %d file descriptors", polli+1);
		rv = poll(pollfd, polli, 10);
		if (rv <= 0) {
			if (rv < 0 && errno != EAGAIN && errno != EINTR)
				RD(1, "poll error %s", strerror(errno));
			continue;
		}

		if (oq) {
			/* try to push packets from the overflow queues
			 * to the corresponding pipes
			 */
			for (i = 0; i < npipes; i++) {
				struct port_des *p = &ports[i];
				struct overflow_queue *q = p->oq;
				struct group_des *g = p->group;
				uint32_t j, lim;
				struct netmap_ring *ring;
				struct netmap_slot *slot;

				if (oq_empty(q))
					continue;
				ring = p->ring;
				lim = nm_ring_space(ring);
				if (!lim)
					continue;
				if (q->n < lim)
					lim = q->n;
				for (j = 0; j < lim; j++) {
					struct netmap_slot s = oq_deq(q), tmp;
					tmp.ptr = 0;
					slot = &ring->slot[ring->cur];
					if (slot->ptr && !g->last) {
						tmp.buf_idx = forward_packet(g + 1, slot);
						/* the forwarding may have removed packets
						 * from the current queue
						 */
						if (q->n < lim)
							lim = q->n;
					} else {
						tmp.buf_idx = slot->buf_idx;
					}
					oq_enq(freeq, &tmp);
					*slot = s;
					slot->flags |= NS_BUF_CHANGED;
					ring->cur = nm_ring_next(ring, ring->cur);
				}
				ring->head = ring->cur;
				forwarded += lim;
				p->ctr.pkts += lim;
			}
		}

		int batch = 0;
		for (i = rxport->nmd->first_rx_ring; i <= rxport->nmd->last_rx_ring; i++) {
			struct netmap_ring *rxring = NETMAP_RXRING(rxport->nmd->nifp, i);

			//D("prepare to scan rings");
			int next_cur = rxring->cur;
			struct netmap_slot *next_slot = &rxring->slot[next_cur];
			const char *next_buf = NETMAP_BUF(rxring, next_slot->buf_idx);
			while (!nm_ring_empty(rxring)) {
				struct netmap_slot *rs = next_slot;
				struct group_des *g = &groups[0];

				// CHOOSE THE CORRECT OUTPUT PIPE
				uint32_t hash = pkt_hdr_hash((const unsigned char *)next_buf, 4, 'B');
				if (hash == 0) {
					non_ip++; // XXX ??
				}
				rs->ptr = hash | (1UL << 32);
				// prefetch the buffer for the next round
				next_cur = nm_ring_next(rxring, next_cur);
				next_slot = &rxring->slot[next_cur];
				next_buf = NETMAP_BUF(rxring, next_slot->buf_idx);
				__builtin_prefetch(next_buf);
				// 'B' is just a hashing seed
				rs->buf_idx = forward_packet(g, rs);
				rs->flags |= NS_BUF_CHANGED;
				rxring->head = rxring->cur = next_cur;

				batch++;
				if (unlikely(batch >= glob_arg.batch)) {
					ioctl(rxport->nmd->fd, NIOCRXSYNC, NULL);
					batch = 0;
				}
				ND(1,
				   "Forwarded Packets: %"PRIu64" Dropped packets: %"PRIu64"   Percent: %.2f",
				   forwarded, dropped,
				   ((float)dropped / (float)forwarded * 100));
			}

		}
	}

	pthread_join(stat_thread, NULL);

	printf("%"PRIu64" packets forwarded.  %"PRIu64" packets dropped. Total %"PRIu64"\n", forwarded,
	       dropped, forwarded + dropped);
	return 0;
}