Выбрать главу

228:  setpgid(newJob.progs[0].pid,newJob.progs[0].pid);

229:

230:  newJob.pgrp = newJob.progs[0].pid;

231:

232:  /* найти идентификатор для задания */

233:  newJob.jobld = 1;

234:  for (job = jobList->head; job; job = job->next)

235:   if (job->jobId >= newJob.jobId)

236:    newJob.jobId = job->jobId+1;

237:

238:  /* задание для списка заданий */

239:  if (!jobList->head) {

240:   job = jobList->head = malloc(sizeof(*job));

241:  } else {

242:   for (job = jobList->head; job->next; job = job->next);

243:   job->next = malloc(sizeof(*job));

244:   job = job->next;

245:  }

246:

247:  *job = newJob;

248:  job->next = NULL;

249:  job->runningProgs = job->numProgs;

250:

251:  if (inBg) {

252:   /* мы не ждем завершения фоновых заданий - добавить

253:      в список фоновых заданий и оставить в покое */

254:

255:   printf("[%d]%d\n", job->jobId,

256:    newJob.progs[newJob.numProgs-1].pid);

257:  } else {

258:   jobList->fg=job;

259:

260:   /* переместить новую группу процессов на передний план */

261:

262:   if (tcsetpgrp(0,newJob.pgrp))

263:    perror("tcsetpgrp");

264:  }

265:

266:  return 0;

267: }

268:

269: void removeJob(struct jobSet *jobList, struct job *job) {

270:  struct job *prevJob;

271:

272:  freeJob(job);

273:  if (job == jobList->head) {

274:   jobList->head=job->next;

275:  } else {

276:   prevJob = jobList->head;

277:   while (prevJob->next != job) prevJob = prevJob->next;

278:   prevJob->next=job->next;

279:  }

280:

281:  free(job);

282: }

283:

284: /* Проверить, завершился ли какой-то из фоновых процессов -

285:    если да, выяснить, почему и определить, завершилось ли задание */

286: void checkJobs(struct jobSet *jobList) {

287:  struct job *job;

288:  pid_t childpid;

289:  int status;

290:  int progNum;

291:

292:  while ((childpid = waitpid(-1, &status, WNOHANG))>0) {

293:   for (job = jobList->head;job;job = job->next) {

294:    progNum = 0;

295:    while (progNum<job->numProgs &&

296:     job->progs[progNum].pid != childpid)

297:     progNum++;

298:    if (progNum<job->numProgs) break;

299:   }

300:

301:   job->runningProgs--;

302:   job->progs[progNum].pid = 0;

303:

304:   if (!job->runningProgs) {

305:    printf(JOB_STATUS_FORMAT,job->jobId,"Готово",

306:     job->text);

307:    removeJob(jobList, job);

308:   }

309:  }

310:

311:  if (childpid == -1 && errno!= ECHILD)

312:   perror("waitpid");

313:  }

314:

315:  int main(int argc, const char **argv) {

316:   char command [MAX_COMMAND_LEN + 1];

317:   char *nextCommand = NULL;

318:   struct jobSetjobList = {NULL, NULL};

319:   struct jobnewJob;

320:   FILE *input = stdin;

321:   int i;

322:   int status;

323:   int inBg;

324:

325:   if (argc>2) {

326:    fprintf(stderr,"Непредвиденные аргументы; использование: ladsh1 "

327:     "<команды>\n");

328:    exit(1);

329:   } else if (argc == 2) {

330:    input = fopen(argv[1], "r");

331:    if (!input) {

332:     perror("fopen");

333:     exit(1);

334:    }

335:   }

336:

337:   /* не обращать внимания на этот сигнал; он только вводит

338:      в заблуждение и не имеет особого значения для оболочки */

339:   signal(SIGTTOU, SIG_IGN);

340:

341:   while(1) {

342:   if (!jobList.fg) {

343:    /* нет заданий переднего плана */

344:

345:    /* проверить, завершились ли какие-то фоновые процессы */

346:    checkJobs(&jobList);

347:

348:    if (!nextCommand) {

349:     if (getCommand(input, command)) break;

350:     nextCommand=command;

351:    }

352:

353:    if (!parseCommand(&nextCommand, &newJob, &inBg) &&

354:     newJob.numProgs) {

355:     runCommand(newJob,&jobList,inBg);

356:    }

357:   } else {

358:    /* задание выполняется на переднем плане; ждать завершения */

359:    i = 0;

360:    while (!jobList.fg->progs[i].pid) i++;

361:

362:    waitpid(jobList.fg->progs[i].pid,&status,0);

363:

364:    jobList.fg->runningProgs--;

365:    jobList.fg->progs[i].pid=0;

366:

367:    if (!jobList.fg->runningProgs) {

368:     /* дочернее завершилось */

369:

370:     removeJob(&jobList, jobList.fg);

371:     jobList.fg = NULL;

372:

373:     /* переместить оболочку на передний план */

374:     if (tcsetpgrp(0, getpid()))

375:      perror("tcsetpgrp");