/* * Ask the user which slice on a the selected disk they want. * Changes ss->selected_slice. */ void fn_select_slice(struct i_fn_args *a) { struct dfui_form *f; struct dfui_action *k; struct dfui_response *r; struct slice *s; char string[16]; f = dfui_form_create( "select_slice", _("Select Primary Partition"), a->short_desc, "", "p", "role", "menu", "p", "special", "dfinstaller_select_slice", NULL ); for (s = disk_slice_first(storage_get_selected_disk(a->s)); s != NULL; s = slice_next(s)) { snprintf(string, 16, "%d", slice_get_number(s)); dfui_form_action_add(f, string, dfui_info_new(slice_get_desc(s), "", "")); } k = dfui_form_action_add(f, "cancel", dfui_info_new(a->cancel_desc, "", "")); dfui_action_property_set(k, "accelerator", "ESC"); if (!dfui_be_present(a->c, f, &r)) abort_backend(); if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { a->result = 0; } else { s = slice_find(storage_get_selected_disk(a->s), atoi(dfui_response_get_action_id(r))); if (s == NULL) { inform(a->c, _("Internal error - response from frontend " "should be a valid slice number.")); a->result = 0; } else { storage_set_selected_slice(a->s, s); a->result = 1; } } dfui_form_free(f); dfui_response_free(r); }
/* * Ask the user which physical disk they want. * Changes ss->selected_disk if successful. */ void fn_select_disk(struct i_fn_args *a) { struct dfui_form *f; struct dfui_action *k; struct dfui_response *r; struct disk *d; f = dfui_form_create( "select_disk", _("Select Disk"), a->short_desc, "", "p", "role", "menu", "p", "special", "dfinstaller_select_disk", NULL ); for (d = storage_disk_first(a->s); d != NULL; d = disk_next(d)) { dfui_form_action_add(f, disk_get_device_name(d), dfui_info_new(disk_get_desc(d), "", "")); } k = dfui_form_action_add(f, "cancel", dfui_info_new(a->cancel_desc, "", "")); dfui_action_property_set(k, "accelerator", "ESC"); if (!dfui_be_present(a->c, f, &r)) abort_backend(); if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { a->result = 0; } else { d = disk_find(a->s, dfui_response_get_action_id(r)); if (d == NULL) { inform(a->c, _("Internal error - response from frontend " "should be a valid device name.")); a->result = 0; } else { storage_set_selected_disk(a->s, d); a->result = 1; } } dfui_form_free(f); dfui_response_free(r); }
/* * Pop a Lua table representing a DFUI field from the Lua stack, * create a new DFUI field from it, and return it. */ static struct dfui_field * dfui_field_from_lua_table(lua_State *L, int table_idx) { struct dfui_field *fi; const char *id, *name, *short_desc, *long_desc; /* * Get the basic properties of the field. */ id = lua_access_table_string(L, table_idx, "id"); name = lua_access_table_string(L, table_idx, "name"); short_desc = lua_access_table_string(L, table_idx, "short_desc"); long_desc = lua_access_table_string(L, table_idx, "long_desc"); /* * Create the initial field. */ fi = dfui_field_new(id, dfui_info_new(name, short_desc, long_desc)); set_dfui_properties_from_lua_table(L, table_idx, DFUI_OBJ_FIELD, fi); lua_pop(L, 1); return(fi); }
/* * Pop a Lua table representing a DFUI action from the Lua stack, * create a new DFUI action from it, and return it. */ static struct dfui_action * dfui_action_from_lua_table(lua_State *L, int table_idx) { struct dfui_action *a; const char *id, *name, *short_desc, *long_desc; /* * Get the basic properties of the action. */ id = lua_access_table_string(L, table_idx, "id"); name = lua_access_table_string(L, table_idx, "name"); short_desc = lua_access_table_string(L, table_idx, "short_desc"); long_desc = lua_access_table_string(L, table_idx, "long_desc"); /* * Create the initial action. */ a = dfui_action_new(id, dfui_info_new(name, short_desc, long_desc)); set_dfui_properties_from_lua_table(L, table_idx, DFUI_OBJ_ACTION, a); lua_pop(L, 1); return(a); }
void state_diagnostics_menu(struct i_fn_args *a) { struct dfui_form *f; struct dfui_action *k; struct dfui_response *r; int done = 0; while (!done) { f = dfui_form_create( "utilities_menu", _("Live CD Diagnostics Menu"), _("These functions can help you diagnose this system."), "", "p", "role", "menu", "a", "show_dmesg", _("Display system startup messages"), _("Display system startup messages (dmesg)"), "", "a", "pciconf", _("Display PCI devices"), _("Display PCI devices (pciconf)"), "", "a", "pnpinfo", _("Display Plug'n'Play ISA devices"), _("Display Plug'n'Play ISA devices (pnpinfo)"), "", "a", "natacontrol", _("Display ATA devices"), _("Display ATA devices (natacontrol)"), "", NULL ); k = dfui_form_action_add(f, "cancel", dfui_info_new(_("Return to Utilities Menu"), "", "")); dfui_action_property_set(k, "accelerator", "ESC"); if (!dfui_be_present(a->c, f, &r)) abort_backend(); /* XXX set up a */ if (strcmp(dfui_response_get_action_id(r), "show_dmesg") == 0) { fn_show_dmesg(a); } else if (strcmp(dfui_response_get_action_id(r), "pciconf") == 0) { fn_show_pciconf(a); } else if (strcmp(dfui_response_get_action_id(r), "pnpinfo") == 0) { fn_show_pnpinfo(a); } else if (strcmp(dfui_response_get_action_id(r), "natacontrol") == 0) { fn_show_natacontrol(a); } else if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { state = state_utilities_menu; done = 1; } dfui_form_free(f); dfui_response_free(r); } }
/* * Execute a series of external utility programs. * Returns 1 if everything executed OK, 0 if one of the * critical commands failed or if the user cancelled. */ int commands_execute(struct i_fn_args *a, struct commands *cmds) { struct dfui_progress *pr; struct command *cmd; int i; int n = 0; int result = 0; int return_val = 1; cmd = cmds->head; while (cmd != NULL) { n++; cmd = cmd->next; } pr = dfui_progress_new(dfui_info_new( "Executing Commands", "Executing Commands", ""), 0); if (!dfui_be_progress_begin(a->c, pr)) abort_backend(); i = 1; for (cmd = cmds->head; cmd != NULL; cmd = cmd->next, i++) { result = command_execute(a, pr, cmd); if (result == COMMAND_RESULT_CANCELLED) { return_val = 0; break; } if (result > 0 && result < 256) { return_val = 0; if (cmd->failure_mode == COMMAND_FAILURE_ABORT) { break; } } dfui_progress_set_amount(pr, (i * 100) / n); } if (!dfui_be_progress_end(a->c)) abort_backend(); dfui_progress_free(pr); return(return_val); }
struct dfui_info * dfui_decode_info(struct aura_buffer *e) { char *name, *short_desc, *long_desc; struct dfui_info *i; name = dfui_decode_string(e); short_desc = dfui_decode_string(e); long_desc = dfui_decode_string(e); i = dfui_info_new(name, short_desc, long_desc); free(name); free(short_desc); free(long_desc); return(i); }
void state_diskutil_menu(struct i_fn_args *a) { struct dfui_form *f; struct dfui_action *k; struct dfui_response *r; int done = 0; while (!done) { f = dfui_form_create( "utilities_menu", _("Disk Utilities Menu"), _("These functions let you manipulate the storage devices " "attached to this computer."), "", "p", "role", "menu", "a", "format_hdd", _("Format a hard disk drive"), "", "", "a", "wipe_start_of_disk", _("Wipe out the start of a disk"), "", "", "a", "wipe_start_of_slice", _("Wipe out the start of a primary partition"), "", "", "a", "install_bootblocks", _("Install bootblocks on disks"), "", "", "a", "format_msdos_floppy", _("Format an MSDOS floppy"), "", "", NULL ); if (is_file("%sboot/cdboot.flp.bz2", a->os_root)) { dfui_form_action_add(f, "create_cdboot_floppy", dfui_info_new(_("Create a CDBoot floppy"), "", "")); } k = dfui_form_action_add(f, "cancel", dfui_info_new(_("Return to Utilities Menu"), "", "")); dfui_action_property_set(k, "accelerator", "ESC"); if (!dfui_be_present(a->c, f, &r)) abort_backend(); /* XXX set up a */ if (strcmp(dfui_response_get_action_id(r), "format_hdd") == 0) { storage_set_selected_disk(a->s, NULL); storage_set_selected_slice(a->s, NULL); fn_format_disk(a); } else if (strcmp(dfui_response_get_action_id(r), "wipe_start_of_disk") == 0) { fn_wipe_start_of_disk(a); } else if (strcmp(dfui_response_get_action_id(r), "wipe_start_of_slice") == 0) { fn_wipe_start_of_slice(a); } else if (strcmp(dfui_response_get_action_id(r), "install_bootblocks") == 0) { a->short_desc = _("Select the disks on which " "you wish to install bootblocks."); a->cancel_desc = _("Return to Utilities Menu"); fn_install_bootblocks(a, NULL); } else if (strcmp(dfui_response_get_action_id(r), "format_msdos_floppy") == 0) { fn_format_msdos_floppy(a); } else if (strcmp(dfui_response_get_action_id(r), "create_cdboot_floppy") == 0) { fn_create_cdboot_floppy(a); } else if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { state = state_utilities_menu; done = 1; } dfui_form_free(f); dfui_response_free(r); } }
/* * state_welcome_system: the start state of the installer state machine, * when run from the installed system. Allow the user to configure the * system. */ void state_welcome_system(struct i_fn_args *a) { struct dfui_form *f; struct dfui_response *r; char msg_buf[2][1024]; snprintf(msg_buf[0], sizeof(msg_buf[0]), _("Configure this %s System"), OPERATING_SYSTEM_NAME); snprintf(msg_buf[1], sizeof(msg_buf[1]), _("Thank you for choosing %s." "\n\n" "For up-to-date news and information on %s, " "make sure to check out" "\n\n" "%s" "\n\n" "You can use this automated application to assist " "you in setting up this %s system." ""), OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_URL, OPERATING_SYSTEM_NAME); f = dfui_form_create( "welcome", msg_buf[0], msg_buf[1], "", "p", "special", "dfinstaller_welcome", NULL ); snprintf(msg_buf[0], sizeof(msg_buf[0]), _("Configure this %s system"), OPERATING_SYSTEM_NAME); dfui_form_action_add(f, "environment", dfui_info_new(_("Configure this System"), msg_buf[0], "")); dfui_form_action_add(f, "utilities", dfui_info_new(_("Utilities"), _("Utilities to work with and diagnose disks and other subsystems"), "")); dfui_form_action_add(f, "exit", dfui_info_new(_("Exit Installer"), _("Exit this program and return to the system"), "")); if (!dfui_be_present(a->c, f, &r)) abort_backend(); if (strcmp(dfui_response_get_action_id(r), "environment") == 0) { state = state_environment_menu; } else if (strcmp(dfui_response_get_action_id(r), "utilities") == 0) { state = state_utilities_menu; } else if (strcmp(dfui_response_get_action_id(r), "exit") == 0) { state = NULL; } else if (strcmp(dfui_response_get_action_id(r), "reboot") == 0) { state = state_reboot; } dfui_form_free(f); dfui_response_free(r); }
/* * state_welcome_livecd: the start state of the installer state machine, * when run from the Live CD. Briefly describe DragonFly to the user, * and present them with a set of reasonable options of how to proceed. */ void state_welcome(struct i_fn_args *a) { struct dfui_form *f; struct dfui_action *k; struct dfui_response *r; char msg_buf[2][1024]; snprintf(msg_buf[0], sizeof(msg_buf[0]), _("Welcome to %s"), OPERATING_SYSTEM_NAME); snprintf(msg_buf[1], sizeof(msg_buf[1]), _("Welcome to the %s Live CD." "\n\n" "%s is an efficient and elegant BSD " "Unix-derived operating system. For more information, see %s" "\n\n" "From this CD, you can boot into %s ``live'' " "(without installing it) to evaluate it, to install it " "manually, or to troubleshoot problems with an " "existing installation, using either a command prompt " "or menu-driven utilities." "\n\n" "Also, you can use this automated application to assist " "you in installing %s on this computer and " "configuring it once it is installed." ""), OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_URL, OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME); if (!a->booted_from_livecd) { state = state_welcome_system; return; } f = dfui_form_create( "welcome", msg_buf[0], msg_buf[1], "", "p", "special", "dfinstaller_welcome", NULL ); if (a->upgrade_menu_toggle) { snprintf(msg_buf[0], sizeof(msg_buf[0]), _("Upgrade a FreeBSD 4.X system to %s"), OPERATING_SYSTEM_NAME); dfui_form_action_add(f, "upgrade", dfui_info_new(_("Upgrade"), msg_buf[0], "")); } else { snprintf(msg_buf[0], sizeof(msg_buf[0]), _("Install %s"), OPERATING_SYSTEM_NAME); snprintf(msg_buf[1], sizeof(msg_buf[1]), _("Install %s on a HDD or HDD partition on this computer"), OPERATING_SYSTEM_NAME); dfui_form_action_add(f, "install", dfui_info_new(msg_buf[0], msg_buf[1], "")); } snprintf(msg_buf[0], sizeof(msg_buf[0]), _("Configure a %s system once it has been installed on HDD"), OPERATING_SYSTEM_NAME); dfui_form_action_add(f, "configure", dfui_info_new(_("Configure an Installed System"), msg_buf[0], "")); dfui_form_action_add(f, "utilities", dfui_info_new(_("Live CD Utilities"), _("Utilities to work with disks, diagnostics, and the LiveCD Environment"), "")); k = dfui_form_action_add(f, "exit", dfui_info_new(_("Exit to Live CD"), _("Exit this program to a login prompt with access to the LiveCD"), "")); dfui_form_action_add(f, "reboot", dfui_info_new(_("Reboot this Computer"), _("Reboot this computer (e.g. to boot into a newly installed system)"), "")); dfui_form_action_add(f, "configure_netboot", dfui_info_new(_("Setup NetBoot Install Services"), _("Setup machine as remote installation server"), "")); if (!dfui_be_present(a->c, f, &r)) abort_backend(); if (strcmp(dfui_response_get_action_id(r), "install") == 0) { state = state_begin_install; } else if (strcmp(dfui_response_get_action_id(r), "upgrade") == 0) { state = state_begin_upgrade; } else if (strcmp(dfui_response_get_action_id(r), "configure") == 0) { storage_set_selected_disk(a->s, NULL); storage_set_selected_slice(a->s, NULL); state = state_configure_menu; } else if (strcmp(dfui_response_get_action_id(r), "utilities") == 0) { state = state_utilities_menu; } else if (strcmp(dfui_response_get_action_id(r), "exit") == 0) { state = NULL; } else if (strcmp(dfui_response_get_action_id(r), "configure_netboot") == 0) { state = state_setup_remote_installation_server; } else if (strcmp(dfui_response_get_action_id(r), "reboot") == 0) { state = state_reboot; } dfui_form_free(f); dfui_response_free(r); }
/* * * state_setup_remote_installation_server: * Setup a remote boot installation environment where a machine * can boot via DHCP/TFTP/NFS and have a running environment * where the installer can setup the machine. * */ void state_setup_remote_installation_server(struct i_fn_args *a) { FILE *p; struct commands *cmds; struct dfui_form *f; struct dfui_action *k; struct dfui_response *r; char *word; char interface[256]; char line[256]; switch (dfui_be_present_dialog(a->c, _("Enable Netboot Installation Services?"), _("Enable NetBoot Installation Services|No thanks"), _("NetBoot Installation Services allows this machine to become " "a Installation Server that will allow the clients to boot over the network " "via PXE and start the Installation Environment." "\n\n*NOTE!* This will assign the IP Address of 10.1.0.1/24 to the selected interface." "\n\nWould you like to provision this machine to serve up the LiveCD/Installer?"))) { case 1: /* * Get interface list. */ p = popen("/sbin/ifconfig -l", "r"); /* XXX it's possible (though extremely unlikely) this will fail. */ while (fgets(line, 255, p) != NULL) line[strlen(line) - 1] = '\0'; pclose(p); f = dfui_form_create( "assign_ip", _("Setup NetBoot Installation Environment"), _("Please select which interface you would like to configure:"), "", "p", "role", "menu", NULL ); /* Loop through array. */ word = strtok(line, " \t"); while (word != NULL) { dfui_form_action_add(f, word, dfui_info_new(word, "", "")); word = strtok(NULL, " "); } k = dfui_form_action_add(f, "cancel", dfui_info_new("Cancel", "", "")); dfui_action_property_set(k, "accelerator", "ESC"); if (!dfui_be_present(a->c, f, &r)) abort_backend(); strlcpy(interface, dfui_response_get_action_id(r), 256); if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { dfui_form_free(f); dfui_response_free(r); return; } /* * * Issues the necessary commands to setup the remote boot environment * */ cmds = commands_new(); command_add(cmds, "%s%s %s 10.1.0.1 netmask 255.255.255.0", a->os_root, cmd_name(a, "IFCONFIG"), interface); command_add(cmds, "%s%s -p %stftpdroot", a->os_root, cmd_name(a, "MKDIR"), a->tmp); command_add(cmds, "%s%s %sboot/pxeboot %stftpdroot", a->os_root, cmd_name(a, "CP"), a->os_root, a->tmp); command_add(cmds, "%s%s %s -ro -alldirs -maproot=root: -network 10.1.0.0 -mask 255.255.255.0 >> %setc/exports", a->os_root, cmd_name(a, "ECHO"), a->os_root, a->os_root); command_add(cmds, "%s%s tftp dgram udp wait root %s%s tftpd -l -s %stftpdroot >> %setc/inetd.conf", a->os_root, cmd_name(a, "ECHO"), a->os_root, cmd_name(a, "TFTPD"), a->tmp, a->os_root); command_add(cmds, "%s%s", a->os_root, cmd_name(a, "INETD")); command_add(cmds, "%s%s %svar/db/dhcpd.leases", a->os_root, cmd_name(a, "TOUCH"), a->os_root); command_add(cmds, "%s%s -cf /etc/dhcpd.conf >%sdev/null 2>&1", a->os_root, cmd_name(a, "DHCPD"), a->os_root); command_add(cmds, "%s%s >%sdev/null 2>&1", a->os_root, cmd_name(a, "RPCBIND"), a->os_root); command_add(cmds, "%s%s -ln >%sdev/null 2>&1", a->os_root, cmd_name(a, "MOUNTD"), a->os_root); command_add(cmds, "%s%s -u -t -n 6 >%sdev/null 2>&1", a->os_root, cmd_name(a, "NFSD"), a->os_root); if (commands_execute(a, cmds)) { inform(a->c, _("NetBoot installation services are now started.")); } else { inform(a->c, _("A failure occurred while provisioning the NetBoot environment. Please check the logs.")); } commands_free(cmds); dfui_form_free(f); dfui_response_free(r); break; case 2: break; }; state = state_welcome; }
static struct dfui_form * make_create_subpartitions_form(struct i_fn_args *a) { struct dfui_form *f; char msg_buf[1][1024]; snprintf(msg_buf[0], sizeof(msg_buf[0]), _("Subpartitions further divide a primary partition for " "use with %s. Some reasons you may want " "a set of subpartitions are:\n\n" "- you want to restrict how much data can be written " "to certain parts of the primary partition, to quell " "denial-of-service attacks; and\n" "- you want to speed up access to data on the disk." ""), OPERATING_SYSTEM_NAME); f = dfui_form_create( "create_subpartitions", _("Create Subpartitions"), _("Set up the subpartitions (also known as just `partitions' " "in BSD tradition) you want to have on this primary " "partition. In most cases you should be fine with " "the default settings.\n\n" "For Capacity, use 'M' to indicate megabytes, 'G' to " "indicate gigabytes, and so on (up to 'E'.) A single '*' " "indicates 'use the remaining space on the primary partition'."), msg_buf[0], "p", "special", "dfinstaller_create_subpartitions", "p", "minimum_width","64", "f", "mountpoint", _("Mountpoint"), "", "", "f", "capacity", _("Capacity"), "", "", "f", "encrypted", _("Encrypted"), "", "", "p", "control", "checkbox", "a", "ok", _("Accept and Create"), "", "", "a", "cancel", (disk_get_formatted(storage_get_selected_disk(a->s)) ? _("Return to Select Disk") : _("Return to Select Primary Partition")), "", "", "p", "accelerator", "ESC", NULL ); dfui_form_set_multiple(f, 1); dfui_form_set_extensible(f, 1); /* * Remove ATM until HAMMER installer support is better * dfui_form_set_extensible(f, 1); */ #if 0 if (expert) { fi = dfui_form_field_add(f, "softupdates", dfui_info_new(_("Softupdates"), "", "")); dfui_field_property_set(fi, "control", "checkbox"); fi = dfui_form_field_add(f, "tmpfsbacked", dfui_info_new(_("TMPFS"), "", "")); dfui_field_property_set(fi, "control", "checkbox"); fi = dfui_form_field_add(f, "fsize", dfui_info_new(_("Frag Sz"), "", "")); fi = dfui_form_field_add(f, "bsize", dfui_info_new(_("Block Sz"), "", "")); dfui_form_action_add(f, "switch", dfui_info_new(_("Switch to Normal Mode"), "", "")); } else { dfui_form_action_add(f, "switch", dfui_info_new(_("Switch to Expert Mode"), "", "")); } #endif return(f); }
/* * Pop a Lua table representing a DFUI form from the Lua stack, * create a new DFUI form from it, and return it. */ static struct dfui_form * dfui_form_from_lua_table(lua_State *L, int table_idx) { struct dfui_form *f; struct dfui_action *a; struct dfui_field *fi; struct dfui_dataset *ds; const char *id, *name, *short_desc, *long_desc; int list_idx, subtable_idx, counter, done; /* * Get the basic properties of the form. */ id = lua_access_table_string(L, table_idx, "id"); name = lua_access_table_string(L, table_idx, "name"); short_desc = lua_access_table_string(L, table_idx, "short_desc"); long_desc = lua_access_table_string(L, table_idx, "long_desc"); /* * Create the initial form. */ f = dfui_form_new(id, dfui_info_new(name, short_desc, long_desc)); set_dfui_properties_from_lua_table(L, table_idx, DFUI_OBJ_FORM, f); /* * Get the list of actions attached to the form. */ lua_pushliteral(L, "actions"); lua_gettable(L, table_idx); list_idx = lua_gettop(L); if (lua_istable(L, list_idx)) { /* * Loop through all entries in this table, creating * and attaching a new action for each one. */ counter = 1; done = 0; while (!done) { lua_pushnumber(L, counter++); lua_gettable(L, list_idx); subtable_idx = lua_gettop(L); if (lua_istable(L, subtable_idx)) { a = dfui_action_from_lua_table(L, subtable_idx); dfui_form_action_attach(f, a); } else { done = 1; } } } else { /* No actions */ } lua_pop(L, 1); /* * Get the list of fields attached to the form. */ lua_pushliteral(L, "fields"); lua_gettable(L, table_idx); list_idx = lua_gettop(L); if (lua_istable(L, list_idx)) { /* * Loop through all entries in this table, creating * and attaching a new field for each one. */ counter = 1; done = 0; while (!done) { lua_pushnumber(L, counter++); lua_gettable(L, list_idx); subtable_idx = lua_gettop(L); if (lua_istable(L, subtable_idx)) { fi = dfui_field_from_lua_table(L, subtable_idx); dfui_form_field_attach(f, fi); } else { done = 1; } } } else { /* No fields */ } lua_pop(L, 1); /* * Get the list of datasets attached to the form. */ lua_pushliteral(L, "datasets"); lua_gettable(L, table_idx); list_idx = lua_gettop(L); if (lua_istable(L, list_idx)) { /* * Loop through all entries in this table, creating * and attaching a new dataset for each one. */ counter = 1; done = 0; while (!done) { lua_pushnumber(L, counter++); lua_gettable(L, list_idx); subtable_idx = lua_gettop(L); if (lua_istable(L, subtable_idx)) { ds = dfui_dataset_from_lua_table(L, subtable_idx); dfui_form_dataset_add(f, ds); } else { done = 1; } } } else { /* No datasets */ } lua_pop(L, 1); /* * Finally, delete the table representing the form by * popping it from the top of the stack. */ lua_pop(L, 1); return(f); }