Constructor for a packagetarget struct
packagetarget_close()

First of all, you have a copy-and-paste error in packagetarget_close(), where you attempt to free target-&gt;min twice, but not target-&gt;max.

Next, note that most of the if statements are superfluous.  As per the standard behaviour for free(),


  If ptr is a null pointer, the function does nothing.


packagetarget_open()

You have undefined behaviour due to the way your error-handling works.  The chunk of memory returned by malloc() contains arbitrary junk.  If packagetarget *target = (packagetarget*) malloc(sizeof(packagetarget)) succeeds, but one of the setters fails, then you would call packagetarget_close(), which would then interpret that arbitrary junk as pointers to memory to be freed.  A good way to fix that is to zero the memory before calling any of the setters.  You can either use calloc() instead of malloc(), or memset(), or a struct initializer.

Avoiding malloc()

In C, I prefer the init-cleanup idiom over new-destroy (which you call open-close).  In the init-cleanup idiom, the caller is responsible for providing the chunk of memory to be initialized, which gives the caller the option of providing either stack-based or heap-based memory.

Avoiding goto

While indiscriminate use of goto leads to spaghetti code, there are some circumstances where goto is justifiable, if used in a readily recognizable pattern.

I think that your use of goto isn't horrible, but personally I would prefer to write the if statements as a chain of &amp;&amp; expressions.

Suggested solution

#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

typedef struct packagetarget {
    char *name;
    char *sys;
    char *arch;
    char *min;
    char *ver;
    char *max;
    linkedlist comp;
} packagetarget;

int packagetarget_setname(packagetarget *target, const char *name) {
    if (!target) return 1;
    if (!name) return 2;
    target-&gt;name = realloc(target-&gt;name, strlen(name) * sizeof(char));
    if (!target-&gt;name) return 3;
    strcpy(target-&gt;name, name);
    return 0;
}

int packagetarget_setsys(packagetarget *target, const char *sys) {
    …
}

int packagetarget_setarch(packagetarget *target, const char *arch) {
    …
}

int packagetarget_setmin(packagetarget *target, const char *min) {
    …
}

int packagetarget_setver(packagetarget *target, const char *ver) {
    …
}

int packagetarget_setmax(packagetarget *target, const char *max) {
    …
}

packagetarget *packagetarget_cleanup(packagetarget *target) {
    if (target) {
        free(target-&gt;name);
        free(target-&gt;sys);
        free(target-&gt;arch);
        free(target-&gt;min);
        free(target-&gt;ver);
        free(target-&gt;max);
        linkedlist_cleanup(&amp;target-&gt;comp);
    }
    return target;
}

packagetarget *packagetarget_init(packagetarget *target) {
    static const packagetarget empty = {};
    if (target) {
        *target = empty;
        if (!(0 == packagetarget_setname(target, "") &amp;&amp;
              0 == packagetarget_setsys(target, PACKAGETARGET_SYS) &amp;&amp;
              0 == packagetarget_setarch(target, PACKAGETARGET_ARCH) &amp;&amp;
              0 == packagetarget_setmin(target, PACKAGETARGET_MIN) &amp;&amp;
              0 == packagetarget_setver(target, PACKAGETARGET_VER) &amp;&amp;
              0 == packagetarget_setmax(target, PACKAGETARGET_MAX) &amp;&amp;
              linkedlist_init(&amp;target-&gt;comp))) {
            packagetarget_cleanup(target);
            return NULL;
        }
    }
    return target;
}

int main() {
    packagetarget t;
    if (packagetarget_init(&amp;t)) {
        …
    }
    packagetarget_cleanup(&amp;t);
}