示例#1
0
文件: efidisk.c 项目: dllinxi/WCET
void
grub_efidisk_fini (void)
{
  free_devices (fd_devices);
  free_devices (hd_devices);
  free_devices (cd_devices);
}
示例#2
0
static void table_destroy(struct dm_table *t)
{
	unsigned int i;

	/* free the indexes (see dm_table_complete) */
	if (t->depth >= 2)
		vfree(t->index[t->depth - 2]);

	/* free the targets */
	for (i = 0; i < t->num_targets; i++) {
		struct dm_target *tgt = t->targets + i;

		if (tgt->type->dtr)
			tgt->type->dtr(tgt);

		dm_put_target_type(tgt->type);
	}

	vfree(t->highs);

	/* free the device list */
	if (t->devices.next != &t->devices) {
		DMWARN("devices still present during destroy: "
		       "dm_table_remove_device calls missing");

		free_devices(&t->devices);
	}

	kfree(t);
}
示例#3
0
void
sane_exit (void)
{
  struct device *dev;

  for (dev = devices_head; dev; dev = dev->next)
    if (dev->dn != -1)
      sane_close(dev); /* implies flush */
  
  free_devices ();
}
示例#4
0
void glwtQuitLinux()
{
    if(glwt.linux_input.inotify_fd > 0)
        close(glwt.linux_input.inotify_fd);

    if(glwt.linux_input.epoll_fd > 0)
        close(glwt.linux_input.epoll_fd);

    free_devices();
    memset(&glwt.linux_input, 0, sizeof(struct glwt_linux_input));
}
示例#5
0
/* Enumerate all disks to name devices.  */
static void
enumerate_disks (void)
{
  struct grub_efidisk_data *devices;

  devices = make_devices ();
  if (! devices)
    return;

  name_devices (devices);
  free_devices (devices);
}
示例#6
0
文件: efidisk.c 项目: dllinxi/WCET
/* Some utility functions to map GRUB devices with EFI devices.  */
grub_efi_handle_t
grub_efidisk_get_current_bdev_handle (void)
{
  struct grub_efidisk_data *d;

  d = get_device_from_drive (current_drive);
  if (d == NULL)
    return NULL;

  if (current_drive == GRUB_INVALID_DRIVE)
    return NULL;

  if (current_drive == cdrom_drive)
    return d->handle;

  if (! (current_drive & 0x80))
    return d->handle;
  /* If this is the whole disk, just return its own data.  */
  else if (current_partition == 0xFFFFFF)
    return d->handle;
  /* Otherwise, we must query the corresponding device to the firmware.  */
  else
    {
      struct grub_efidisk_data *devices;
      grub_efi_handle_t handle = 0;
      auto int find_partition (struct grub_efidisk_data *c);

      int find_partition (struct grub_efidisk_data *c)
	{
	  grub_efi_hard_drive_device_path_t hd;

	  grub_memcpy (&hd, c->last_device_path, sizeof (hd));

	  if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
	       == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
	      && (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
		  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
	      && (part_start == hd.partition_start))
	    {
	      handle = c->handle;
	      return 1;
	    }

	  return 0;
	}

      devices = make_devices ();
      iterate_child_devices (devices, d, find_partition);
      free_devices (devices);

      if (handle != 0)
	return handle;
    }
示例#7
0
int fpga_free_model(struct fpga_model* model)
{
	int rc;

	if (!model) return 0;
	rc = model->rc;
	free_devices(model);
	free(model->tmp_str);
	strarray_free(&model->str);
	free(model->tiles);
	free_xc6_routing_bitpos(model->sw_bitpos);
	memset(model, 0, sizeof(*model));
	return rc;
}
示例#8
0
SANE_Status
sane_get_devices (const SANE_Device *** device_list, SANE_Bool local)
{
  SANEI_Config config;
  struct device *dev;
  int dev_count;
  int i;

  DBG (3, "%s: %p, %d\n", __FUNCTION__, (const void *)device_list, local);

  if (devlist) {
    if (device_list)
      *device_list = devlist;
    return SANE_STATUS_GOOD;
  }

  free_devices ();

  config.count = 0;
  config.descriptors = NULL;
  config.values = NULL;
  sanei_configure_attach (XEROX_CONFIG_FILE, &config, list_conf_devices);

  for (dev_count = 0, dev = devices_head; dev; dev = dev->next)
    dev_count++;

  devlist = malloc ((dev_count + 1) * sizeof (*devlist));
  if (!devlist)
    {
      DBG (1, "%s: malloc: no memory\n", __FUNCTION__);
      return SANE_STATUS_NO_MEM;
    }

  for (i = 0, dev = devices_head; dev; dev = dev->next)
    devlist[i++] = &dev->sane;
  devlist[i++] = NULL;

  if (device_list)
    *device_list = devlist;
  return SANE_STATUS_GOOD;
}
示例#9
0
static int enable_all_gpus(Options *op, XConfigPtr config,
                           XConfigLayoutPtr layout)
{
    DevicesPtr pDevices;
    int i;

    pDevices = find_devices(op);
    if (!pDevices) {
        nv_error_msg("Unable to determine number of GPUs in system; cannot "
                     "honor '--enable-all-gpus' option.");
        return FALSE;
    }
    
    /* free all existing X screens, monitors, devices, and adjacencies */
    
    xconfigFreeScreenList(&config->screens);
    xconfigFreeDeviceList(&config->devices);
    xconfigFreeMonitorList(&config->monitors);
    xconfigFreeAdjacencyList(&layout->adjacencies);

    /* add N new screens; this will also add device and monitor sections */
    
    for (i = 0; i < pDevices->nDevices; i++) {
        xconfigGenerateAddScreen(config,
                                 pDevices->devices[i].dev.bus,
                                 pDevices->devices[i].dev.domain,
                                 pDevices->devices[i].dev.slot,
                                 pDevices->devices[i].name, i,
                                 "nvidia", "NVIDIA Corporation");
    }
    
    free_devices(pDevices);

    /* create adjacencies for the layout */
    
    create_adjacencies(op, config, layout);

    return TRUE;
    
} /* enable_all_gpus() */
示例#10
0
static void nm_backend_data_cleanup(struct connline_context *context)
{
    struct nm_dbus *nm = context->backend_data;

    if (nm == NULL)
        return;

    if (nm->state_watched == TRUE)
        connline_dbus_remove_watch(context->dbus_cnx,
                                   NM_STATE_SIGNAL_MATCH_RULE, watch_nm_state, context);

    if (nm->call != NULL) {
        dbus_pending_call_cancel(nm->call);
        dbus_pending_call_unref(nm->call);
    }

    free_devices(nm);

    free(nm);

    context->backend_data = NULL;
}
示例#11
0
/*
 * get_screens_to_clone() - try to detect automatically how many heads has each
 * device in order to use that number to create more than two separate X
 * screens. If the user specifies the option --num-x-screens <quantity>, that
 * value is used. If neither the user specifies the quantity or the number of
 * heads can be detected automatically, it uses 2 heads (the standard
 * behavior). This function returns an array of size nscreens with the number
 * of screens to clone per screen candidate. The caller is responsible of
 * freeing the memory of that array.
 */
static int* get_screens_to_clone(Options *op,
                                 const XConfigScreenPtr *screen_candidates,
                                 int nscreens)
{
    DevicesPtr pDevices;
    int *screens_to_clone, *supported_screens;
    int i, j, devs_found;

    screens_to_clone = nvalloc(nscreens * sizeof(int));
    supported_screens = nvalloc(nscreens * sizeof(int));

    /* Detect the number of supported screens per screen candidate */
    devs_found = FALSE;
    pDevices = find_devices(op);
    if (pDevices) {
        for (i = 0; i < nscreens; i++) {
            int bus, slot, scratch;

            if (!screen_candidates[i]) {
                continue;
            }

            /* parse the bus id for this candidate screen */
            if (!xconfigParsePciBusString(screen_candidates[i]->device->busid,
                                          &bus, &slot, &scratch)) {
                continue;
            }

            for (j = 0; j < pDevices->nDevices; j++) {
                if ((pDevices->devices[j].dev.bus == bus) &&
                    (pDevices->devices[j].dev.slot == slot)) {

                    if (pDevices->devices[j].crtcs > 0) {
                        supported_screens[i] = pDevices->devices[j].crtcs;
                    }
                    break;
                }
            }
        }
        free_devices(pDevices);
        devs_found = TRUE;
    }

    /* If user has defined a number of screens per GPU, use that value */
    if (op->num_x_screens > 0) {
        for (i = 0; i < nscreens; i++) {
            if (!screen_candidates[i]) {
                continue;
            }

            /* Print error when user specifies more X screens than supported */
            if (devs_found && op->num_x_screens > supported_screens[i]) {
                nv_warning_msg("Number of X screens specified is higher than the "
                               "supported quantity (%d)", supported_screens[i]);
            }

            screens_to_clone[i] = op->num_x_screens;
        }

        goto done;
    }

    for (i = 0; i < nscreens; i++) {
        if (screen_candidates[i]) {
            if (devs_found) {
                /* If devices found, use the supported screens number */
                screens_to_clone[i] = supported_screens[i];
            }
            else {
                /* Default behavior (2 heads per GPU) */
                screens_to_clone[i] = 2;
            }
        }
    }

done:
    nvfree(supported_screens);
    return screens_to_clone;
}
示例#12
0
static int enable_separate_x_screens(Options *op, XConfigPtr config,
                                     XConfigLayoutPtr layout)
{
    XConfigScreenPtr screen, *screenlist = NULL;
    XConfigAdjacencyPtr adj;
    int* screens_to_clone = NULL;

    int i, nscreens = 0;
    int have_busids;
    
    /* step 1: build the list of screens that are candidate to be cloned */
    
    if (op->screen) {
        screen = xconfigFindScreen(op->screen, config->screens);
        if (!screen) {
            nv_error_msg("Unable to find screen '%s'.", op->screen);
            return FALSE;
        }
        
        screenlist = nvalloc(sizeof(XConfigScreenPtr));
        screenlist[0] = screen;
        nscreens = 1;
        
    } else {
        for (adj = layout->adjacencies; adj; adj = adj->next) {
            nscreens++;
            screenlist = realloc(screenlist,
                                 sizeof(XConfigScreenPtr) * nscreens);
            
            screenlist[nscreens-1] = adj->screen;
        }
    }
    
    if (!nscreens) return FALSE;
    
    /* step 2: do all screens in the list have a bus ID? */
    
    have_busids = TRUE;
    
    for (i = 0; i < nscreens; i++) {
        if (screenlist[i] &&
            screenlist[i]->device &&
            screenlist[i]->device->busid) {
            // this screen has a busid
        } else {
            have_busids = FALSE;
            break;
        }
    }
    
    /*
     * if not everyone has a bus id, then let's assign bus ids to all
     * the screens; XXX what if _some_ already have busids?  Too bad,
     * we're going to reassign all of them.
     */
    
    if (!have_busids) {
        DevicesPtr pDevices;
        
        pDevices = find_devices(op);
        if (!pDevices) {
            nv_error_msg("Unable to determine number or location of "
                         "GPUs in system; cannot "
                         "honor '--separate-x-screens' option.");
            return FALSE;
        }
        
        for (i = 0; i < nscreens; i++) {
            if (i >= pDevices->nDevices) {
                /*
                 * we have more screens than GPUs, this screen is no
                 * longer a candidate
                 */
                screenlist[i] = NULL;
                continue;
            }
            
            screenlist[i]->device->busid = nvalloc(32);
            xconfigFormatPciBusString(screenlist[i]->device->busid, 32,
                                      pDevices->devices[i].dev.domain,
                                      pDevices->devices[i].dev.bus,
                                      pDevices->devices[i].dev.slot, 0);

            screenlist[i]->device->board = nvstrdup(pDevices->devices[i].name);
        }

        free_devices(pDevices);
    }

    /* step 3 */
    clean_screen_list(screenlist, config, nscreens);
    
    /* step 4 */
    screens_to_clone = get_screens_to_clone(op, screenlist, nscreens);
    
    /* step 5: clone each eligible screen */
    
    for (i = 0; i < nscreens; i++) {
        if (!screenlist[i]) continue;

        while (--screens_to_clone[i] > 0) {
            clone_screen(screenlist[i], screens_to_clone[i]);
        }
    }

    nvfree(screens_to_clone);
    
    /* step 6: wipe the existing adjacencies and recreate them */
    
    xconfigFreeAdjacencyList(&layout->adjacencies);
    
    create_adjacencies(op, config, layout);

    /* free unused device and monitor sections */
    
    free_unused_devices(op, config);
    free_unused_monitors(op, config);

    /* free stuff */

    free(screenlist);

    return TRUE;

} /* enable_separate_x_screens() */
示例#13
0
DevicesPtr find_devices(Options *op)
{
    DevicesPtr pDevices = NULL;
    DisplayDevicePtr pDisplayDevice;
    int i, j, n, count = 0;
    unsigned int mask, bit;
    DeviceRec tmpDevice;
    NvCfgPciDevice *devs = NULL;
    NvCfgBool is_primary_device;
    NvCfgBool ret;
    char *lib_path;
    void *lib_handle;

    NvCfgBool (*__getDevices)(int *n, NvCfgDevice **devs);
    NvCfgBool (*__openDevice)(int bus, int slot, NvCfgDeviceHandle *handle);
    NvCfgBool (*__getPciDevices)(int *n, NvCfgPciDevice **devs);
    NvCfgBool (*__openPciDevice)(int domain, int bus, int slot, int function,
                                 NvCfgDeviceHandle *handle);
    NvCfgBool (*__getNumCRTCs)(NvCfgDeviceHandle handle, int *crtcs);
    NvCfgBool (*__getProductName)(NvCfgDeviceHandle handle, char **name);
    NvCfgBool (*__getDisplayDevices)(NvCfgDeviceHandle handle,
                                     unsigned int *display_device_mask);
    NvCfgBool (*__getEDID)(NvCfgDeviceHandle handle,
                           unsigned int display_device,
                           NvCfgDisplayDeviceInformation *info);
    NvCfgBool (*__isPrimaryDevice)(NvCfgDeviceHandle handle,
                                  NvCfgBool *is_primary_device);
    NvCfgBool (*__closeDevice)(NvCfgDeviceHandle handle);
    NvCfgBool (*__getDeviceUUID)(NvCfgDeviceHandle handle, char **uuid);
    
    /* dlopen() the nvidia-cfg library */
    
#define __LIB_NAME "libnvidia-cfg.so.1"

    if (op->nvidia_cfg_path) {
        lib_path = nvstrcat(op->nvidia_cfg_path, "/", __LIB_NAME, NULL);
    } else {
        lib_path = strdup(__LIB_NAME);
    }
    
    lib_handle = dlopen(lib_path, RTLD_NOW);
    
    nvfree(lib_path);
    
    if (!lib_handle) {
        nv_warning_msg("error opening %s: %s.", __LIB_NAME, dlerror());
        return NULL;
    }
    
#define __GET_FUNC(proc, name)                                        \
    (proc) = dlsym(lib_handle, (name));                               \
    if (!(proc)) {                                                    \
        nv_warning_msg("error retrieving symbol %s from %s: %s",      \
                       (name), __LIB_NAME, dlerror());                \
        dlclose(lib_handle);                                          \
        return NULL;                                                  \
    }

    /* required functions */
    __GET_FUNC(__getDevices, "nvCfgGetDevices");
    __GET_FUNC(__openDevice, "nvCfgOpenDevice");
    __GET_FUNC(__getPciDevices, "nvCfgGetPciDevices");
    __GET_FUNC(__openPciDevice, "nvCfgOpenPciDevice");
    __GET_FUNC(__getNumCRTCs, "nvCfgGetNumCRTCs");
    __GET_FUNC(__getProductName, "nvCfgGetProductName");
    __GET_FUNC(__getDisplayDevices, "nvCfgGetDisplayDevices");
    __GET_FUNC(__getEDID, "nvCfgGetEDID");
    __GET_FUNC(__closeDevice, "nvCfgCloseDevice");
    __GET_FUNC(__getDeviceUUID, "nvCfgGetDeviceUUID");

    /* optional functions */
    __isPrimaryDevice = dlsym(lib_handle, "nvCfgIsPrimaryDevice");
    
    if (__getPciDevices(&count, &devs) != NVCFG_TRUE) {
        return NULL;
    }

    if (count == 0) return NULL;

    pDevices = nvalloc(sizeof(DevicesRec));
    
    pDevices->devices = nvalloc(sizeof(DeviceRec) * count);

    pDevices->nDevices = count;

    for (i = 0; i < count; i++) {
        
        pDevices->devices[i].dev = devs[i];
        
        if (__openPciDevice(devs[i].domain, devs[i].bus, devs[i].slot, 0,
                            &(pDevices->devices[i].handle)) != NVCFG_TRUE) {
            goto fail;
        }
        
        if (__getNumCRTCs(pDevices->devices[i].handle,
                          &pDevices->devices[i].crtcs) != NVCFG_TRUE) {
            goto fail;
        }

        if (__getProductName(pDevices->devices[i].handle,
                             &pDevices->devices[i].name) != NVCFG_TRUE) {
            /* This call may fail with little impact to the Device section */
            pDevices->devices[i].name = NULL;
        }

        if (__getDeviceUUID(pDevices->devices[i].handle,
                            &pDevices->devices[i].uuid) != NVCFG_TRUE) {
            goto fail;
        }
        if (__getDisplayDevices(pDevices->devices[i].handle, &mask) !=
            NVCFG_TRUE) {
            goto fail;
        }
        
        pDevices->devices[i].displayDeviceMask = mask;

        /* count the number of display devices */
        
        for (n = j = 0; j < 32; j++) {
            if (mask & (1 << j)) n++;
        }
        
        pDevices->devices[i].nDisplayDevices = n;

        if (n) {

            /* allocate the info array of the right size */
            
            pDevices->devices[i].displayDevices =
                nvalloc(sizeof(DisplayDeviceRec) * n);
            
            /* fill in the info array */
            
            for (n = j = 0; j < 32; j++) {
                bit = 1 << j;
                if (!(bit & mask)) continue;
                
                pDisplayDevice = &pDevices->devices[i].displayDevices[n];
                pDisplayDevice->mask = bit;

                if (__getEDID(pDevices->devices[i].handle, bit,
                              &pDisplayDevice->info) != NVCFG_TRUE) {
                    pDisplayDevice->info_valid = FALSE;
                } else {
                    pDisplayDevice->info_valid = TRUE;
                }
                n++;
            }
        } else {
            pDevices->devices[i].displayDevices = NULL;
        }

        if ((i != 0) && (__isPrimaryDevice != NULL) &&
            (__isPrimaryDevice(pDevices->devices[i].handle,
                               &is_primary_device) == NVCFG_TRUE) &&
            (is_primary_device == NVCFG_TRUE)) {
            memcpy(&tmpDevice, &pDevices->devices[0], sizeof(DeviceRec));
            memcpy(&pDevices->devices[0], &pDevices->devices[i], sizeof(DeviceRec));
            memcpy(&pDevices->devices[i], &tmpDevice, sizeof(DeviceRec));
        }
        
        ret = __closeDevice(pDevices->devices[i].handle);
        pDevices->devices[i].handle = NULL;

        if (ret != NVCFG_TRUE) {
            goto fail;
        }
    }
    
    goto done;
    
 fail:

    nv_warning_msg("Unable to use the nvidia-cfg library to query NVIDIA "
                   "hardware.");

    for (i = 0; i < pDevices->nDevices; i++) {
        /* close the opened device */
        if (pDevices->devices[i].handle) {
            __closeDevice(pDevices->devices[i].handle);
        }
    }

    free_devices(pDevices);
    pDevices = NULL;

    /* fall through */

 done:
    
    if (devs) free(devs);
    
    return pDevices;
    
} /* find_devices() */
示例#14
0
static void nm_devices_cb(DBusPendingCall *pending, void *user_data)
{
    struct connline_context *context = user_data;
    char **devices_obj = NULL;
    DBusMessageIter arg;
    DBusMessage *reply;
    struct nm_dbus *nm;
    int len;
    int i;

    if (dbus_pending_call_get_completed(pending) == FALSE)
        return;

    nm = context->backend_data;
    nm->call = NULL;

    reply = dbus_pending_call_steal_reply(pending);
    if (reply == NULL)
        goto error;

    if (dbus_message_iter_init(reply, &arg) == FALSE)
        goto error;

    if (connline_dbus_get_array(&arg, DBUS_TYPE_OBJECT_PATH,
                                &len, &devices_obj) < 0)
        goto error;

    if (devices_obj != NULL && len > 0) {
        free_devices(nm);

        nm->nb_devices = len;
        nm->devices = calloc(nm->nb_devices, sizeof(char *));
        if (nm->devices == NULL)
            goto error;

        for (i = 0; i < len; i++) {
            nm->devices[i] = strdup(devices_obj[i]);
            if (nm->devices[i] == NULL) {
                nm->nb_devices = i;
                goto error;
            }
        }

        nm->current_device = 0;

        if (nm_device_get_all(context) < 0)
            goto error;

        free(devices_obj);
    }

    dbus_message_unref(reply);
    dbus_pending_call_unref(pending);

    return;

error:
    free(devices_obj);

    if (reply != NULL)
        dbus_message_unref(reply);

    dbus_pending_call_unref(pending);

    nm_backend_data_cleanup(context);
    __connline_call_error_callback(context, false);
}
示例#15
0
    static void nm_device_all_cb(DBusPendingCall *pending, void *user_data)
{
    struct connline_context *context = user_data;
    char ip[INET_ADDRSTRLEN+1];
    char **properties = NULL;
    unsigned int dev_state;
    unsigned int dev_type;
    const char *interface;
    dbus_bool_t managed;
    DBusMessageIter arg;
    DBusMessage *reply;
    struct nm_dbus *nm;
    struct in_addr in4;
    unsigned int ip4;

    if (dbus_pending_call_get_completed(pending) == FALSE)
        return;

    nm = context->backend_data;
    nm->call = NULL;

    reply = dbus_pending_call_steal_reply(pending);
    if (reply == NULL)
        goto error;

    if (dbus_message_iter_init(reply, &arg) == FALSE)
        goto error;

    if (connline_dbus_get_dict_entry_basic(&arg, "Managed",
                                           DBUS_TYPE_BOOLEAN, &managed) < 0)
        goto error;

    if (managed == FALSE)
        goto next;

    if (connline_dbus_get_dict_entry_basic(&arg, "State",
                                           DBUS_TYPE_UINT32, &dev_state) < 0)
        goto error;

    if (dev_state != NM_DEVICE_STATE_ACTIVATED)
        goto next;

    if (connline_dbus_get_dict_entry_basic(&arg, "DeviceType",
                                           DBUS_TYPE_UINT32, &dev_type) < 0)
        goto error;

    nm->bearer = nm_device_type_to_bearer(dev_type);
    if (!(context->bearer_type == CONNLINE_BEARER_UNKNOWN ||
            nm->bearer & context->bearer_type))
        goto next;

    __connline_call_connected_callback(context);

    free_devices(nm);

    if (connline_dbus_get_dict_entry_basic(&arg, "Ip4Address",
                                           DBUS_TYPE_UINT32, &ip4) < 0)
        goto error;

    memset(ip, 0, INET_ADDRSTRLEN+1);

    in4.s_addr = ip4;

    if (inet_ntop(AF_INET, &in4, ip, INET_ADDRSTRLEN+1) == NULL)
        goto error;

    if (connline_dbus_get_dict_entry_basic(&arg, "IpInterface",
                                           DBUS_TYPE_STRING, &interface) < 0)
        goto error;

    properties = insert_into_property_list(properties, "bearer",
                                           connline_bearer_to_string(nm->bearer));

    properties = insert_into_property_list(properties,
                                           "interface", interface);

    properties = insert_into_property_list(properties, "address", ip);

    if (properties != NULL)
        __connline_call_property_callback(context, properties);

    goto out;

next:
    nm->current_device++;

    if (nm->current_device < nm->nb_devices) {
        if (nm_device_get_all(context) < 0)
            goto error;
    } else {
        free_devices(nm);

        __connline_call_disconnected_callback(context);
    }

out:
    dbus_message_unref(reply);
    dbus_pending_call_unref(pending);

    return;

error:
    if (reply != NULL)
        dbus_message_unref(reply);

    dbus_pending_call_unref(pending);

    nm_backend_data_cleanup(context);
    __connline_call_error_callback(context, false);
}
示例#16
0
/* PAM entry point for authentication verification */
int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc,
                        const char **argv)
{

  struct passwd *pw = NULL, pw_s;
  const char *user = NULL;

  cfg_t cfg_st;
  cfg_t *cfg = &cfg_st;
  char buffer[BUFSIZE];
  char *buf = NULL;
  char *authfile_dir;
  int authfile_dir_len;
  int pgu_ret, gpn_ret;
  int retval = PAM_IGNORE;
  device_t *devices = NULL;
  unsigned n_devices = 0;

  parse_cfg(flags, argc, argv, cfg);

  if (!cfg->origin) {
    if (!strcpy(buffer, DEFAULT_ORIGIN_PREFIX)) {
      DBG(("Unable to create origin string"));
      goto done;
    }

    if (gethostname
        (buffer + strlen(DEFAULT_ORIGIN_PREFIX),
         BUFSIZE - strlen(DEFAULT_ORIGIN_PREFIX)) == -1) {
      DBG(("Unable to get host name"));
      goto done;
    }
    DBG(("Origin not specified, using \"%s\"", buffer));
    cfg->origin = strdup(buffer);
  }

  if (!cfg->origin) {
    DBG(("Unable to allocate memory"));
    goto done;
  }

  if (!cfg->appid) {
    DBG(("Appid not specified, using the same value of origin (%s)",
         cfg->origin));
    cfg->appid = strdup(cfg->origin);
  }

  if (!cfg->appid) {
    DBG(("Unable to allocate memory"));
    goto done;
  }

  if (cfg->max_devs == 0) {
    DBG(("Maximum devices number not set. Using default (%d)", MAX_DEVS));
    cfg->max_devs = MAX_DEVS;
  }

  devices = malloc(sizeof(device_t) * cfg->max_devs);
  if (!devices) {
    DBG(("Unable to allocate memory"));
    return PAM_IGNORE;
  }

  pgu_ret = pam_get_user(pamh, &user, NULL);
  if (pgu_ret != PAM_SUCCESS || user == NULL) {
    DBG(("Unable to access user %s", user));
    free(devices);
    devices = NULL;
    return PAM_CONV_ERR;
  }

  DBG(("Requesting authentication for user %s", user));

  gpn_ret = getpwnam_r(user, &pw_s, buffer, sizeof(buffer), &pw);
  if (gpn_ret != 0 || pw == NULL || pw->pw_dir == NULL
      || pw->pw_dir[0] != '/') {
    DBG(("Unable to retrieve credentials for user %s, (%s)", user,
         strerror(errno)));
    retval = PAM_USER_UNKNOWN;
    goto done;
  }

  DBG(("Found user %s", user));
  DBG(("Home directory for %s is %s", user, pw->pw_dir));

  if (!cfg->auth_file) {
    buf = NULL;
    authfile_dir = secure_getenv(DEFAULT_AUTHFILE_DIR_VAR);
    if (!authfile_dir) {
      DBG(("Variable %s is not set. Using default value ($HOME/.config/)",
           DEFAULT_AUTHFILE_DIR_VAR));
      authfile_dir_len =
          strlen(pw->pw_dir) + strlen("/.config") +
          strlen(DEFAULT_AUTHFILE) + 1;
      buf = malloc(sizeof(char) * (authfile_dir_len));

      if (!buf) {
        DBG(("Unable to allocate memory"));
        retval = PAM_IGNORE;
        goto done;
      }

      strcpy(buf, pw->pw_dir);
      strcat(buf, "/.config");
      strcat(buf, DEFAULT_AUTHFILE);
    } else {
      DBG(("Variable %s set to %s", DEFAULT_AUTHFILE_DIR_VAR,
           authfile_dir));
      authfile_dir_len =
          strlen(authfile_dir) + strlen(DEFAULT_AUTHFILE) + 1;
      buf = malloc(sizeof(char) * (authfile_dir_len));

      if (!buf) {
        DBG(("Unable to allocate memory"));
        retval = PAM_IGNORE;
        goto done;
      }

      strcpy(buf, authfile_dir);
      strcat(buf, DEFAULT_AUTHFILE);
    }

    DBG(("Using default authentication file %s", buf));

    cfg->auth_file = strdup(buf);
    if (!cfg->auth_file) {
      DBG(("Unable to allocate memory"));
      retval = PAM_IGNORE;
      goto done;
    }

    free(buf);
    buf = NULL;
  } else {
    DBG(("Using authentication file %s", cfg->auth_file));
  }
  retval =
      get_devices_from_authfile(cfg->auth_file, user, cfg->max_devs,
                                cfg->debug, devices, &n_devices);
  if (retval != 1) {
    DBG(("Unable to get devices from file %s", cfg->auth_file));
    retval = PAM_AUTHINFO_UNAVAIL;
    goto done;
  }

  if (n_devices == 0) {
    if (cfg->nouserok) {
      DBG(("Found no devices but nouserok specified. Skipping authentication"));
      retval = PAM_SUCCESS;
      goto done;
    } else {
      DBG(("Found no devices. Aborting."));
      retval = PAM_AUTHINFO_UNAVAIL;
      goto done;
    }
  }

  if (cfg->manual == 0) {
    if (cfg->interactive) {
      converse(pamh, PAM_PROMPT_ECHO_ON,
               "Insert your U2F device, then press ENTER.\n");
    }

    retval = do_authentication(cfg, devices, n_devices, pamh);
  } else {
    retval = do_manual_authentication(cfg, devices, n_devices, pamh);
  }

  if (retval != 1) {
    DBG(("do_authentication returned %d", retval));
    retval = PAM_AUTH_ERR;
    goto done;
  }

  retval = PAM_SUCCESS;

done:
  free_devices(devices, n_devices);

  if (buf) {
    free(buf);
    buf = NULL;
  }

  if (cfg->alwaysok && retval != PAM_SUCCESS) {
    DBG(("alwaysok needed (otherwise return with %d)", retval));
    retval = PAM_SUCCESS;
  }
  DBG(("done. [%s]", pam_strerror(pamh, retval)));

  return retval;

}