Changeset 41655


Ignore:
Timestamp:
Nov 8, 2008, 10:50:42 AM (9 years ago)
Author:
toby@…
Message:

SystemCmd:

  • fix major leak (circbuf only freed when command exited non-zero)
  • fix fd leak
  • minor refactoring
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/base/src/pextlib1.0/Pextlib.c

    r41651 r41655  
    221221        Tcl_Obj *errbuf;
    222222        Tcl_Obj *tcl_result;
    223 
    224         if (objc != 2 && objc != 3) {
    225                 Tcl_WrongNumArgs(interp, 1, objv, "command");
    226                 return TCL_ERROR;
    227         }
    228        
    229         if (objc == 3) {
     223        int read_failed, status;
     224
     225        /* usage: system [-notty] command */
     226        if (objc == 2) {
     227                cmdstring = Tcl_GetString(objv[1]);
     228        } else if (objc == 3) {
    230229                char *arg = Tcl_GetString(objv[1]);
    231230                cmdstring = Tcl_GetString(objv[2]);
    232231
    233                 if (!strcmp(arg, "-notty")) {
     232                if (strcmp(arg, "-notty") == 0) {
    234233                        osetsid = 1;
    235234                } else {
     
    240239                }
    241240        } else {
    242                 cmdstring = Tcl_GetString(objv[1]);
    243         }
    244 
    245         if (pipe(fdset) == -1)
    246                 return TCL_ERROR;
     241                Tcl_WrongNumArgs(interp, 1, objv, "command");
     242                return TCL_ERROR;
     243        }
    247244
    248245        /*
     
    250247         * popen() itself is not used because stderr is also desired.
    251248         */
     249        if (pipe(fdset) != 0) {
     250                return TCL_ERROR;
     251        }
     252
    252253        pid = fork();
    253         if (pid == -1)
    254                 return TCL_ERROR;
    255         if (pid == 0) {
     254        switch (pid) {
     255        case -1: /* error */
     256                return TCL_ERROR;
     257                break;
     258        case 0: /* child */
    256259                close(fdset[0]);
     260
    257261                if ((nullfd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
    258262                        _exit(1);
     
    272276                execve("/bin/sh", args, environ);
    273277                _exit(1);
    274         }
     278                break;
     279        default: /* parent */
     280                break;
     281        }
     282
    275283        close(fdset[1]);
    276         pdes = fdopen(fdset[0], "r");
    277284
    278285        /* read from simulated popen() pipe */
     286        read_failed = 0;
    279287        pos = 0;
    280288        bzero(circbuf, sizeof(circbuf));
     289        pdes = fdopen(fdset[0], "r");
    281290        while ((buf = fgetln(pdes, &linelen)) != NULL) {
    282291                char *sbuf;
     
    299308
    300309                if (sbuf == NULL) {
    301                         for (fline = pos; pos < fline + CBUFSIZ; pos++) {
    302                                 if (circbuf[pos % CBUFSIZ].len != 0)
    303                                         free(circbuf[pos % CBUFSIZ].line);
    304                         }
    305                         return TCL_ERROR;
     310                        read_failed = 1;
     311                        break;
    306312                }
    307313
     
    313319                circbuf[pos].len = slen;
    314320
    315                 if (pos++ == CBUFSIZ - 1)
     321                if (pos++ == CBUFSIZ - 1) {
    316322                        pos = 0;
    317                 ret = ui_info(interp, sbuf);
    318                 if (ret != TCL_OK) {
    319                         for (fline = pos; pos < fline + CBUFSIZ; pos++) {
    320                                 if (circbuf[pos % CBUFSIZ].len != 0)
    321                                         free(circbuf[pos % CBUFSIZ].line);
    322                         }
    323                         return ret;
     323                }
     324
     325                if (ui_info(interp, sbuf) != TCL_OK) {
     326                        read_failed = 1;
     327                        break;
    324328                }
    325329        }
    326330        fclose(pdes);
    327331
    328         if (wait(&ret) != pid)
    329                 return TCL_ERROR;
    330         if (WIFEXITED(ret)) {
    331                 if (WEXITSTATUS(ret) == 0)
    332                         return TCL_OK;
    333                 else {
     332        status = TCL_ERROR;
     333
     334        if (wait(&ret) == pid && WIFEXITED(ret) && !read_failed) {
     335                /* Normal exit, and reading from the pipe didn't fail. */
     336                if (WEXITSTATUS(ret) == 0) {
     337                        status = TCL_OK;
     338                } else {
    334339                        /* Copy the contents of the circular buffer to errbuf */
    335340                        Tcl_Obj* errorCode;
     
    345350                                /* Re-add previously stripped newline */
    346351                                Tcl_AppendToObj(errbuf, "\n", 1);
    347                                 free(circbuf[pos % CBUFSIZ].line);
    348352                        }
    349353
     
    363367                        Tcl_AppendObjToObj(tcl_result, errbuf);
    364368                        Tcl_SetObjResult(interp, tcl_result);
    365                         return TCL_ERROR;
    366                 }
    367         } else
    368                 return TCL_ERROR;
     369                }
     370        }
     371
     372        /* Cleanup. */
     373        close(fdset[0]);
     374        for (fline = 0; fline < CBUFSIZ; fline++) {
     375                if (circbuf[fline].len != 0) {
     376                        free(circbuf[fline].line);
     377                }
     378        }
     379
     380        return status;
    369381}
    370382
Note: See TracChangeset for help on using the changeset viewer.