]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/fsck.c
hwclock: free temporary variable before return
[thirdparty/util-linux.git] / disk-utils / fsck.c
index 299a775254d15ee855fe79b0bedf5bbba2561375..7dc12e67ade090dd0958a00c4f50da295d3b827e 100644 (file)
@@ -1,4 +1,12 @@
 /*
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
  * fsck --- A generic, parallelizing front-end for the fsck program.
  * It will automatically try to run fsck programs in parallel if the
  * devices are on separate spindles.  It is based on the same ideas as
  *              2001, 2002, 2003, 2004, 2005 by  Theodore Ts'o.
  *
  * Copyright (C) 2009-2014 Karel Zak <kzak@redhat.com>
- *
- * This file may be redistributed under the terms of the GNU Public
- * License.
  */
-
 #define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */
 
 #include <sys/types.h>
 #include "pathnames.h"
 #include "exitcodes.h"
 #include "c.h"
-#include "closestream.h"
 #include "fileutils.h"
 #include "monotonic.h"
+#include "strutils.h"
 
 #define XALLOC_EXIT_CODE       FSCK_EX_ERROR
 #include "xalloc.h"
 
+#define CLOSE_EXIT_CODE                FSCK_EX_ERROR
+#include "closestream.h"
+
 #ifndef DEFAULT_FSTYPE
 # define DEFAULT_FSTYPE        "ext2"
 #endif
@@ -86,7 +93,7 @@ static const char *really_wanted[] = {
 };
 
 /*
- * Internal structure for mount tabel entries.
+ * Internal structure for mount table entries.
  */
 struct fsck_fs_data
 {
@@ -141,11 +148,12 @@ static int progress;
 static int progress_fd;
 static int force_all_parallel;
 static int report_stats;
+static FILE *report_stats_file;
 
 static int num_running;
 static int max_running;
 
-static volatile int cancel_requested;
+static volatile sig_atomic_t cancel_requested;
 static int kill_sent;
 static char *fstype;
 static struct fsck_instance *instance_list;
@@ -165,11 +173,12 @@ static int string_to_int(const char *s)
        long l;
        char *p;
 
+       errno = 0;
        l = strtol(s, &p, 0);
-       if (*p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX)
+       if (errno || *p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX)
                return -1;
-       else
-               return (int) l;
+
+       return (int) l;
 }
 
 /* Do we really really want to check this fs? */
@@ -312,7 +321,7 @@ static int is_irrotational_disk(dev_t disk)
                        "/sys/dev/block/%d:%d/queue/rotational",
                        major(disk), minor(disk));
 
-       if (rc < 0 || (unsigned int) (rc + 1) > sizeof(path))
+       if (rc < 0 || (unsigned int) rc >= sizeof(path))
                return 0;
 
        f = fopen(path, "r");
@@ -394,7 +403,6 @@ done:
                inst->lockpath = NULL;
        }
        free(diskpath);
-       return;
 }
 
 static void unlock_disk(struct fsck_instance *inst)
@@ -406,7 +414,6 @@ static void unlock_disk(struct fsck_instance *inst)
                printf(_("Unlocking %s.\n"), inst->lockpath);
 
        close(inst->lock);                      /* unlock */
-       unlink(inst->lockpath);
 
        free(inst->lockpath);
 
@@ -422,7 +429,6 @@ static void free_instance(struct fsck_instance *i)
        free(i->lockpath);
        mnt_unref_fs(i->fs);
        free(i);
-       return;
 }
 
 static struct libmnt_fs *add_dummy_fs(const char *device)
@@ -466,8 +472,8 @@ static void fs_interpret_type(struct libmnt_fs *fs)
 static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)),
                        const char *filename, int line)
 {
-       warnx(_("%s: parse error at line %d -- ignore"), filename, line);
-       return 0;
+       warnx(_("%s: parse error at line %d -- ignored"), filename, line);
+       return 1;
 }
 
 /*
@@ -487,7 +493,7 @@ static void load_fs_info(void)
        errno = 0;
 
        /*
-        * Let's follow libmount defauls if $FSTAB_FILE is not specified
+        * Let's follow libmount defaults if $FSTAB_FILE is not specified
         */
        path = getenv("FSTAB_FILE");
 
@@ -537,25 +543,34 @@ static struct libmnt_fs *lookup(char *path)
 }
 
 /* Find fsck program for a given fs type. */
-static char *find_fsck(const char *type)
+static int find_fsck(const char *type, char **progpath)
 {
        char *s;
        const char *tpl;
-       static char prog[256];
+       char *prog = NULL;
        char *p = xstrdup(fsck_path);
-       struct stat st;
+       int rc;
 
        /* Are we looking for a program or just a type? */
        tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
 
        for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
-               sprintf(prog, tpl, s, type);
-               if (stat(prog, &st) == 0)
+               xasprintf(&prog, tpl, s, type);
+               if (access(prog, X_OK) == 0)
                        break;
+               free(prog);
+               prog = NULL;
        }
+
        free(p);
+       rc = prog ? 1 : 0;
+
+       if (progpath)
+               *progpath = prog;
+       else
+               free(prog);
 
-       return(s ? prog : NULL);
+       return rc;
 }
 
 static int progress_active(void)
@@ -579,23 +594,39 @@ static int progress_active(void)
  */
 static void print_stats(struct fsck_instance *inst)
 {
-       struct timeval delta;
+       struct timeval delta = { 0 };
 
        if (!inst || !report_stats || noexecute)
                return;
 
        timersub(&inst->end_time, &inst->start_time, &delta);
 
-       fprintf(stdout, "%s: status %d, rss %ld, "
-                       "real %ld.%06ld, user %d.%06d, sys %d.%06d\n",
-               fs_get_device(inst->fs),
-               inst->exit_status,
-               inst->rusage.ru_maxrss,
-               delta.tv_sec, delta.tv_usec,
-               (int)inst->rusage.ru_utime.tv_sec,
-               (int)inst->rusage.ru_utime.tv_usec,
-               (int)inst->rusage.ru_stime.tv_sec,
-               (int)inst->rusage.ru_stime.tv_usec);
+       if (report_stats_file)
+               fprintf(report_stats_file, "%s %d %ld"
+                                  " %"PRId64".%06"PRId64
+                                  " %"PRId64".%06"PRId64
+                                  " %"PRId64".%06"PRId64"\n",
+                       fs_get_device(inst->fs),
+                       inst->exit_status,
+                       inst->rusage.ru_maxrss,
+                       (int64_t)delta.tv_sec, (int64_t)delta.tv_usec,
+                       (int64_t)inst->rusage.ru_utime.tv_sec,
+                       (int64_t)inst->rusage.ru_utime.tv_usec,
+                       (int64_t)inst->rusage.ru_stime.tv_sec,
+                       (int64_t)inst->rusage.ru_stime.tv_usec);
+       else
+               fprintf(stdout, "%s: status %d, rss %ld, "
+                               "real %"PRId64".%06"PRId64", "
+                               "user %"PRId64".%06"PRId64", "
+                               "sys %"PRId64".%06"PRId64"\n",
+                       fs_get_device(inst->fs),
+                       inst->exit_status,
+                       inst->rusage.ru_maxrss,
+                       (int64_t)delta.tv_sec, (int64_t)delta.tv_usec,
+                       (int64_t)inst->rusage.ru_utime.tv_sec,
+                       (int64_t)inst->rusage.ru_utime.tv_usec,
+                       (int64_t)inst->rusage.ru_stime.tv_sec,
+                       (int64_t)inst->rusage.ru_stime.tv_usec);
 }
 
 /*
@@ -618,26 +649,25 @@ static int execute(const char *progname, const char *progpath,
        for (i=0; i <num_args; i++)
                argv[argc++] = xstrdup(args[i]);
 
-       if (progress) {
-               if ((strcmp(type, "ext2") == 0) ||
-                   (strcmp(type, "ext3") == 0) ||
-                   (strcmp(type, "ext4") == 0) ||
-                   (strcmp(type, "ext4dev") == 0)) {
-                       char tmp[80];
-
-                       tmp[0] = 0;
-                       if (!progress_active()) {
-                               snprintf(tmp, 80, "-C%d", progress_fd);
-                               inst->flags |= FLAG_PROGRESS;
-                       } else if (progress_fd)
-                               snprintf(tmp, 80, "-C%d", progress_fd * -1);
-                       if (tmp[0])
-                               argv[argc++] = xstrdup(tmp);
-               }
+       if (progress &&
+              ((strcmp(type, "ext2") == 0) ||
+               (strcmp(type, "ext3") == 0) ||
+               (strcmp(type, "ext4") == 0) ||
+               (strcmp(type, "ext4dev") == 0))) {
+
+               char tmp[80];
+               tmp[0] = 0;
+               if (!progress_active()) {
+                       snprintf(tmp, 80, "-C%d", progress_fd);
+                       inst->flags |= FLAG_PROGRESS;
+               } else if (progress_fd)
+                       snprintf(tmp, 80, "-C%d", progress_fd * -1);
+               if (tmp[0])
+                       argv[argc++] = xstrdup(tmp);
        }
 
        argv[argc++] = xstrdup(fs_get_device(fs));
-       argv[argc] = 0;
+       argv[argc] = NULL;
 
        if (verbose || noexecute) {
                const char *tgt = mnt_fs_get_target(fs);
@@ -704,6 +734,8 @@ static int kill_all(int signum)
        for (inst = instance_list; inst; inst = inst->next) {
                if (inst->flags & FLAG_DONE)
                        continue;
+               if (inst->pid <= 0)
+                       continue;
                kill(inst->pid, signum);
                n++;
        }
@@ -727,7 +759,7 @@ static struct fsck_instance *wait_one(int flags)
 
        if (noexecute) {
                inst = instance_list;
-               prev = 0;
+               prev = NULL;
 #ifdef RANDOM_DEBUG
                while (inst->next && (random() & 1)) {
                        prev = inst;
@@ -762,7 +794,7 @@ static struct fsck_instance *wait_one(int flags)
                        warn(_("waitpid failed"));
                        continue;
                }
-               for (prev = 0, inst = instance_list;
+               for (prev = NULL, inst = instance_list;
                     inst;
                     prev = inst, inst = inst->next) {
                        if (inst->pid == pid)
@@ -798,17 +830,17 @@ static struct fsck_instance *wait_one(int flags)
                for (inst2 = instance_list; inst2; inst2 = inst2->next) {
                        if (inst2->flags & FLAG_DONE)
                                continue;
-                       if (strcmp(inst2->type, "ext2") &&
+                       if (strcmp(inst2->type, "ext2") != 0 &&
                            strcmp(inst2->type, "ext3") &&
-                           strcmp(inst2->type, "ext4") &&
-                           strcmp(inst2->type, "ext4dev"))
+                           strcmp(inst2->type, "ext4") != 0 &&
+                           strcmp(inst2->type, "ext4dev") != 0)
                                continue;
                        /*
                         * If we've just started the fsck, wait a tiny
                         * bit before sending the kill, to give it
                         * time to set up the signal handler
                         */
-                       if (inst2->start_time.tv_sec < time(0) + 2) {
+                       if (inst2->start_time.tv_sec < time(NULL) + 2) {
                                if (fork() == 0) {
                                        sleep(1);
                                        kill(inst2->pid, SIGUSR1);
@@ -870,9 +902,9 @@ static int wait_many(int flags)
  * If the type isn't specified by the user, then use either the type
  * specified in /etc/fstab, or DEFAULT_FSTYPE.
  */
-static int fsck_device(struct libmnt_fs *fs, int interactive)
+static int fsck_device(struct libmnt_fs *fs, int interactive, int warn_notfound)
 {
-       char progname[80], *progpath;
+       char *progname, *progpath;
        const char *type;
        int retval;
 
@@ -882,33 +914,39 @@ static int fsck_device(struct libmnt_fs *fs, int interactive)
 
        if (type && strcmp(type, "auto") != 0)
                ;
-       else if (fstype && strncmp(fstype, "no", 2) &&
-           strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) &&
+       else if (fstype && strncmp(fstype, "no", 2) != 0 &&
+           strncmp(fstype, "opts=", 5) != 0 && strncmp(fstype, "loop", 4) != 0 &&
            !strchr(fstype, ','))
                type = fstype;
        else
                type = DEFAULT_FSTYPE;
 
-       sprintf(progname, "fsck.%s", type);
-       progpath = find_fsck(progname);
-       if (progpath == NULL) {
+       xasprintf(&progname, "fsck.%s", type);
+
+       if (!find_fsck(progname, &progpath)) {
+               free(progname);
                if (fs_check_required(type)) {
                        retval = ENOENT;
                        goto err;
                }
+               if (warn_notfound)
+                       warnx(_("fsck.%s not found; ignore %s"), type,
+                                       fs_get_device(fs));
                return 0;
        }
 
        num_running++;
        retval = execute(progname, progpath, type, fs, interactive);
+       free(progname);
+       free(progpath);
        if (retval) {
                num_running--;
                goto err;
        }
        return 0;
 err:
-       warnx(_("error %d (%m) while executing fsck.%s for %s"),
-                       retval, type, fs_get_device(fs));
+       warnx(_("error %d (%s) while executing fsck.%s for %s"),
+                       retval, strerror(errno), type, fs_get_device(fs));
        return FSCK_EX_ERROR;
 }
 
@@ -916,7 +954,7 @@ err:
 /*
  * Deal with the fsck -t argument.
  */
-struct fs_type_compile {
+static struct fs_type_compile {
        char **list;
        int *type;
        int  negate;
@@ -1014,7 +1052,7 @@ static int fs_match(struct libmnt_fs *fs, struct fs_type_compile *cmp)
        int n, ret = 0, checked_type = 0;
        char *cp;
 
-       if (cmp->list == 0 || cmp->list[0] == 0)
+       if (cmp->list == NULL || cmp->list[0] == NULL)
                return 1;
 
        for (n=0; (cp = cmp->list[n]); n++) {
@@ -1061,7 +1099,7 @@ static int fs_ignored_type(struct libmnt_fs *fs)
 {
        const char **ip, *type;
 
-       if (mnt_fs_is_netfs(fs) || mnt_fs_is_pseudofs(fs) || mnt_fs_is_swaparea(fs))
+       if (!mnt_fs_is_regularfs(fs))
                return 1;
 
        type = mnt_fs_get_fstype(fs);
@@ -1135,7 +1173,7 @@ static int ignore(struct libmnt_fs *fs)
 
 
        /* See if the <fsck.fs> program is available. */
-       if (find_fsck(type) == NULL) {
+       if (!find_fsck(type, NULL)) {
                if (fs_check_required(type))
                        warnx(_("cannot check %s: fsck.%s not found"),
                                fs_get_device(fs), type);
@@ -1160,7 +1198,7 @@ static int count_slaves(dev_t disk)
        if (!(dir = opendir(dirname)))
                return -1;
 
-       while ((dp = readdir(dir)) != 0) {
+       while ((dp = readdir(dir)) != NULL) {
 #ifdef _DIRENT_HAVE_D_TYPE
                if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
                        continue;
@@ -1202,7 +1240,7 @@ static int disk_already_active(struct libmnt_fs *fs)
         * Don't check a stacked device with any other disk too.
         */
        if (!disk || fs_is_stacked(fs))
-               return (instance_list != 0);
+               return (instance_list != NULL);
 
        for (inst = instance_list; inst; inst = inst->next) {
                dev_t idisk = fs_get_disk(inst->fs, 0);
@@ -1252,7 +1290,7 @@ static int check_all(void)
                        if (!skip_root &&
                            !fs_is_done(fs) &&
                            !(ignore_mounted && is_mounted(fs))) {
-                               status |= fsck_device(fs, 1);
+                               status |= fsck_device(fs, 1, 0);
                                status |= wait_many(FLAG_WAIT_ALL);
                                if (status > FSCK_EX_NONDESTRUCT) {
                                        mnt_free_iter(itr);
@@ -1265,7 +1303,7 @@ static int check_all(void)
 
        /*
         * This is for the bone-headed user who enters the root
-        * filesystem twice.  Skip root will skep all root entries.
+        * filesystem twice.  Skip root will skip all root entries.
         */
        if (skip_root) {
                mnt_reset_iter(itr, MNT_ITER_FORWARD);
@@ -1315,7 +1353,7 @@ static int check_all(void)
                        /*
                         * Spawn off the fsck process
                         */
-                       status |= fsck_device(fs, serialize);
+                       status |= fsck_device(fs, serialize, 0);
                        fs_set_done(fs);
 
                        /*
@@ -1354,8 +1392,9 @@ static int check_all(void)
        return status;
 }
 
-static void __attribute__((__noreturn__)) usage(FILE *out)
+static void __attribute__((__noreturn__)) usage(void)
 {
+       FILE *out = stdout;
        fputs(USAGE_HEADER, out);
        fprintf(out, _(" %s [options] -- [fs-options] [<filesystem> ...]\n"),
                         program_invocation_short_name);
@@ -1371,51 +1410,61 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
        fputs(_(" -N         do not execute, just show what would be done\n"), out);
        fputs(_(" -P         check filesystems in parallel, including root\n"), out);
        fputs(_(" -R         skip root filesystem; useful only with '-A'\n"), out);
-       fputs(_(" -r         report statistics for each device checked\n"), out);
+       fputs(_(" -r [<fd>]  report statistics for each device checked;\n"
+               "            file descriptor is for GUIs\n"), out);
        fputs(_(" -s         serialize the checking operations\n"), out);
        fputs(_(" -T         do not show the title on startup\n"), out);
        fputs(_(" -t <type>  specify filesystem types to be checked;\n"
-               "             <type> is allowed to be a comma-separated list\n"), out);
+               "            <type> is allowed to be a comma-separated list\n"), out);
        fputs(_(" -V         explain what is being done\n"), out);
-       fputs(_(" -?         display this help and exit\n"), out);
 
+       fputs(USAGE_SEPARATOR, out);
+       fprintf(out, " -?, --help     %s\n", USAGE_OPTSTR_HELP);
+       fprintf(out, "     --version  %s\n", USAGE_OPTSTR_VERSION);
        fputs(USAGE_SEPARATOR, out);
        fputs(_("See the specific fsck.* commands for available fs-options."), out);
        fprintf(out, USAGE_MAN_TAIL("fsck(8)"));
-
-       exit(out == stderr ? FSCK_EX_USAGE : FSCK_EX_OK);
+       exit(FSCK_EX_OK);
 }
 
 static void signal_cancel(int sig __attribute__((__unused__)))
 {
-       cancel_requested++;
+       cancel_requested = 1;
 }
 
 static void parse_argv(int argc, char *argv[])
 {
        int     i, j;
-       char    *arg, *dev, *tmp = 0;
+       char    *arg, *dev, *tmp = NULL;
        char    options[128];
        int     opt = 0;
        int     opts_for_fsck = 0;
        struct sigaction        sa;
+       int     report_stats_fd = -1;
 
        /*
         * Set up signal action
         */
        memset(&sa, 0, sizeof(struct sigaction));
        sa.sa_handler = signal_cancel;
-       sigaction(SIGINT, &sa, 0);
-       sigaction(SIGTERM, &sa, 0);
+       sigaction(SIGINT, &sa, NULL);
+       sigaction(SIGTERM, &sa, NULL);
 
        num_devices = 0;
        num_args = 0;
-       instance_list = 0;
+       instance_list = NULL;
 
        for (i=1; i < argc; i++) {
                arg = argv[i];
                if (!arg)
                        continue;
+
+               /* the only two longopts to satisfy UL standards */
+               if (!opts_for_fsck && !strcmp(arg, "--help"))
+                       usage();
+               if (!opts_for_fsck && !strcmp(arg, "--version"))
+                       print_version(FSCK_EX_OK);
+
                if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
                        if (num_devices >= MAX_DEVICES)
                                errx(FSCK_EX_ERROR, _("too many devices"));
@@ -1504,20 +1553,30 @@ static void parse_argv(int argc, char *argv[])
                                break;
                        case 'r':
                                report_stats = 1;
+                               if (arg[j+1]) {                                 /* -r<fd> */
+                                       report_stats_fd = strtou32_or_err(arg+j+1, _("invalid argument of -r"));
+                                       goto next_arg;
+                               } else if (i+1 < argc && *argv[i+1] >= '0' && *argv[i+1] <= '9') {      /* -r <fd> */
+                                       report_stats_fd = strtou32_or_err(argv[i+1], _("invalid argument of -r"));
+                                       ++i;
+                                       goto next_arg;
+                               }
                                break;
                        case 's':
                                serialize = 1;
                                break;
                        case 't':
-                               tmp = 0;
+                               tmp = NULL;
                                if (fstype)
-                                       usage(stderr);
+                                       errx(FSCK_EX_USAGE,
+                                               _("option '%s' may be specified only once"), "-t");
                                if (arg[j+1])
                                        tmp = arg+j+1;
                                else if ((i+1) < argc)
                                        tmp = argv[++i];
                                else
-                                       usage(stderr);
+                                       errx(FSCK_EX_USAGE,
+                                               _("option '%s' requires an argument"), "-t");
                                fstype = xstrdup(tmp);
                                compile_fs_type(fstype, &fs_type_compiled);
                                goto next_arg;
@@ -1525,7 +1584,7 @@ static void parse_argv(int argc, char *argv[])
                                opts_for_fsck++;
                                break;
                        case '?':
-                               usage(stdout);
+                               usage();
                                break;
                        default:
                                options[++opt] = arg[j];
@@ -1542,10 +1601,20 @@ static void parse_argv(int argc, char *argv[])
                        opt = 0;
                }
        }
+
+       /* Validate the report stats file descriptor to avoid disasters */
+       if (report_stats_fd >= 0) {
+               report_stats_file = fdopen(report_stats_fd, "w");
+               if (!report_stats_file)
+                       err(FSCK_EX_ERROR,
+                               _("invalid argument of -r: %d"),
+                               report_stats_fd);
+       }
+
        if (getenv("FSCK_FORCE_ALL_PARALLEL"))
                force_all_parallel++;
-       if ((tmp = getenv("FSCK_MAX_INST")))
-           max_running = atoi(tmp);
+       if (ul_strtos32(getenv("FSCK_MAX_INST"), &max_running, 10) != 0)
+               max_running = 0;
 }
 
 int main(int argc, char *argv[])
@@ -1562,16 +1631,29 @@ int main(int argc, char *argv[])
        setlocale(LC_CTYPE, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
+       strutils_set_exitcode(FSCK_EX_USAGE);
        mnt_init_debug(0);              /* init libmount debug mask */
        mntcache = mnt_new_cache();     /* no fatal error if failed */
 
+       if (mntcache)
+               /* Force libblkid to accept also filesystems with bad
+                * checksums. This feature is helpful for "fsck /dev/foo," but
+                * if it evaluates LABEL/UUIDs from fstab, then libmount may
+                * use cached data from udevd and udev accepts only properly
+                * detected filesystems.
+                */
+               mnt_cache_set_sbprobe(mntcache, BLKID_SUBLKS_BADCSUM);
+
+
        parse_argv(argc, argv);
 
        if (!notitle)
                printf(UTIL_LINUX_VERSION);
 
+       signal(SIGCHLD, SIG_DFL);       /* clear any inherited settings */
+
        load_fs_info();
 
        fsck_path = xstrdup(path && *path ? path : FSCK_DEFAULT_PATH);
@@ -1609,7 +1691,7 @@ int main(int argc, char *argv[])
                        continue;
                if (ignore_mounted && is_mounted(fs))
                        continue;
-               status |= fsck_device(fs, interactive);
+               status |= fsck_device(fs, interactive, interactive);
                if (serialize ||
                    (max_running && (num_running >= max_running))) {
                        struct fsck_instance *inst;