| 1 | #ifndef lint | 
| 2 | static const char       RCSid[] = "$Id: rpiece.c,v 2.68 2025/07/01 19:40:35 greg Exp $"; | 
| 3 | #endif | 
| 4 | /* | 
| 5 | * Generate sections of a picture. | 
| 6 | */ | 
| 7 |  | 
| 8 |  | 
| 9 | #include <stdio.h> | 
| 10 | #include <signal.h> | 
| 11 | #include <sys/types.h> | 
| 12 |  | 
| 13 | #include "platform.h" | 
| 14 | #ifndef NON_POSIX /* XXX need abstraction for process management */ | 
| 15 | #include <sys/wait.h> | 
| 16 | #endif | 
| 17 |  | 
| 18 | #include "standard.h" | 
| 19 | #include "color.h" | 
| 20 | #include "view.h" | 
| 21 | #include "rtprocess.h" | 
| 22 |  | 
| 23 | #ifndef F_SETLKW | 
| 24 |  | 
| 25 | int | 
| 26 | main( | 
| 27 | int argc, | 
| 28 | char *argv[] | 
| 29 | ) | 
| 30 | { | 
| 31 | fprintf(stderr, "%s: no NFS lock manager on this machine\n", argv[0]); | 
| 32 | exit(1); | 
| 33 | } | 
| 34 |  | 
| 35 | #else | 
| 36 |  | 
| 37 | #ifndef NFS | 
| 38 | #define  NFS                    1 | 
| 39 | #endif | 
| 40 |  | 
| 41 | #ifndef RHAS_FORK_EXEC | 
| 42 | #undef MAXFORK | 
| 43 | #define MAXFORK                 0 | 
| 44 | #endif | 
| 45 | #ifndef MAXFORK | 
| 46 | #if NFS | 
| 47 | #define  MAXFORK                3       /* allotment of duped processes */ | 
| 48 | #else | 
| 49 | #define  MAXFORK                0 | 
| 50 | #endif | 
| 51 | #endif | 
| 52 | /* protection from SYSV signals(!) */ | 
| 53 | #if defined(sgi) | 
| 54 | #define guard_io()      sighold(SIGALRM) | 
| 55 | #define unguard()       sigrelse(SIGALRM) | 
| 56 | #endif | 
| 57 | #ifndef guard_io | 
| 58 | #define guard_io() | 
| 59 | #define unguard() | 
| 60 | #endif | 
| 61 |  | 
| 62 | /* rpict command */ | 
| 63 | char  *rpargv[128] = {"rpict", "-S", "1"}; | 
| 64 | int  rpargc = 3; | 
| 65 | FILE  *torp, *fromrp; | 
| 66 | COLR  *pbuf; | 
| 67 | /* our view parameters */ | 
| 68 | VIEW  ourview = STDVIEW; | 
| 69 | double  pixaspect = 1.0; | 
| 70 | int  hres = 1024, vres = 1024, hmult = 4, vmult = 4; | 
| 71 | /* output file */ | 
| 72 | char  *outfile = NULL; | 
| 73 | int  outfd; | 
| 74 | long  scanorig; | 
| 75 | FILE  *syncfp = NULL;           /* synchronization file pointer */ | 
| 76 | int  synclst = F_UNLCK;         /* synchronization file lock status */ | 
| 77 | int  nforked = 0; | 
| 78 |  | 
| 79 | #define  sflock(t)      if ((t)!=synclst) dolock(fileno(syncfp),synclst=t) | 
| 80 |  | 
| 81 | int  verbose = 0; | 
| 82 | int  nowarn = 0; | 
| 83 | unsigned  timelim = 0; | 
| 84 | int  rvrlim = -1; | 
| 85 |  | 
| 86 | int  gotalrm = 0; | 
| 87 | void  onalrm(int i) { gotalrm++; } | 
| 88 |  | 
| 89 | static void dolock(int  fd, int  ltyp); | 
| 90 | static void init(int  ac, char  **av); | 
| 91 | static int nextpiece(int        *xp, int        *yp); | 
| 92 | static int rvrpiece(int *xp, int        *yp); | 
| 93 | static int cleanup(int  rstat); | 
| 94 | static void rpiece(void); | 
| 95 | static int putpiece(int xpos, int       ypos); | 
| 96 | static void filerr(char  *t); | 
| 97 |  | 
| 98 |  | 
| 99 | int | 
| 100 | main( | 
| 101 | int  argc, | 
| 102 | char  *argv[] | 
| 103 | ) | 
| 104 | { | 
| 105 | int  i, rval; | 
| 106 |  | 
| 107 | fixargv0(argv[0]);                      /* assigns global progname */ | 
| 108 | for (i = 1; i < argc; i++) { | 
| 109 | /* expand arguments */ | 
| 110 | while ((rval = expandarg(&argc, &argv, i)) > 0) | 
| 111 | ; | 
| 112 | if (rval < 0) { | 
| 113 | fprintf(stderr, "%s: cannot expand '%s'\n", | 
| 114 | argv[0], argv[i]); | 
| 115 | exit(1); | 
| 116 | } | 
| 117 | if (argv[i][0] == '-') | 
| 118 | switch (argv[i][1]) { | 
| 119 | case 'w': | 
| 120 | if (!argv[i][2]) | 
| 121 | nowarn = !nowarn; | 
| 122 | else if (argv[i][2] == '+') | 
| 123 | nowarn = 0; | 
| 124 | else if (argv[i][2] == '-') | 
| 125 | nowarn = 1; | 
| 126 | break; | 
| 127 | case 'v': | 
| 128 | switch (argv[i][2]) { | 
| 129 | case '\0':      /* verbose option */ | 
| 130 | verbose = !verbose; | 
| 131 | continue; | 
| 132 | case 'f':       /* view file */ | 
| 133 | if (viewfile(argv[++i], &ourview, NULL) <= 0) { | 
| 134 | fprintf(stderr, | 
| 135 | "%s: not a view file\n", argv[i]); | 
| 136 | exit(1); | 
| 137 | } | 
| 138 | continue; | 
| 139 | default:        /* view option? */ | 
| 140 | rval = getviewopt(&ourview, argc-i, argv+i); | 
| 141 | if (rval >= 0) { | 
| 142 | i += rval; | 
| 143 | continue; | 
| 144 | } | 
| 145 | break; | 
| 146 | } | 
| 147 | break; | 
| 148 | case 'p':               /* pixel aspect ratio? */ | 
| 149 | if (argv[i][2] == 'm') { | 
| 150 | fprintf(stderr, "%s: -pm unsupported\n", | 
| 151 | argv[0]); | 
| 152 | ++i; | 
| 153 | continue; | 
| 154 | } | 
| 155 | if (argv[i][2] == 'X') { | 
| 156 | fprintf(stderr, "%s: -pXYZ unsupported\n", | 
| 157 | argv[0]); | 
| 158 | ++i; | 
| 159 | continue; | 
| 160 | } | 
| 161 | if (argv[i][2] == 'c') { | 
| 162 | fprintf(stderr, "%s: -pc unsupported\n", | 
| 163 | argv[0]); | 
| 164 | i += 9; | 
| 165 | continue; | 
| 166 | } | 
| 167 | if (argv[i][2] != 'a' || argv[i][3]) | 
| 168 | break; | 
| 169 | pixaspect = atof(argv[++i]); | 
| 170 | continue; | 
| 171 | case 'S': | 
| 172 | fprintf(stderr, "%s: -S unsupported\n", argv[0]); | 
| 173 | i++; | 
| 174 | continue; | 
| 175 | case 'T':               /* time limit (hours) */ | 
| 176 | if (argv[i][2]) | 
| 177 | break; | 
| 178 | timelim = atof(argv[++i])*3600. + .5; | 
| 179 | continue; | 
| 180 | case 'x':               /* overall x resolution */ | 
| 181 | if (argv[i][2]) | 
| 182 | break; | 
| 183 | hres = atoi(argv[++i]); | 
| 184 | continue; | 
| 185 | case 'y':               /* overall y resolution */ | 
| 186 | if (argv[i][2]) | 
| 187 | break; | 
| 188 | vres = atoi(argv[++i]); | 
| 189 | continue; | 
| 190 | case 'X':               /* horizontal multiplier */ | 
| 191 | if (argv[i][2]) | 
| 192 | break; | 
| 193 | hmult = atoi(argv[++i]); | 
| 194 | continue; | 
| 195 | case 'Y':               /* vertical multiplier */ | 
| 196 | if (argv[i][2]) | 
| 197 | break; | 
| 198 | vmult = atoi(argv[++i]); | 
| 199 | continue; | 
| 200 | case 'R':               /* recover */ | 
| 201 | if (argv[i][2]) | 
| 202 | break; | 
| 203 | rvrlim = 0; | 
| 204 | /* fall through */ | 
| 205 | case 'F':               /* syncronization file */ | 
| 206 | if (argv[i][2]) | 
| 207 | break; | 
| 208 | if ((syncfp = | 
| 209 | fdopen(open(argv[++i],O_RDWR|O_CREAT,0666),"r+")) == NULL) { | 
| 210 | fprintf(stderr, "%s: cannot open\n", | 
| 211 | argv[i]); | 
| 212 | exit(1); | 
| 213 | } | 
| 214 | continue; | 
| 215 | case 'z':               /* z-file ist verbotten */ | 
| 216 | fprintf(stderr, "%s: -z option not allowed\n", | 
| 217 | argv[0]); | 
| 218 | exit(1); | 
| 219 | case 'o':               /* output file */ | 
| 220 | if (argv[i][2]) | 
| 221 | break; | 
| 222 | outfile = argv[++i]; | 
| 223 | continue; | 
| 224 | } | 
| 225 | else if (i >= argc-1) | 
| 226 | break; | 
| 227 | rpargv[rpargc++] = argv[i]; | 
| 228 | } | 
| 229 | if (i >= argc) { | 
| 230 | fprintf(stderr, "%s: missing octree argument\n", argv[0]); | 
| 231 | exit(1); | 
| 232 | } | 
| 233 | if (outfile == NULL) { | 
| 234 | fprintf(stderr, "%s: missing output file\n", argv[0]); | 
| 235 | exit(1); | 
| 236 | } | 
| 237 | init(argc, argv); | 
| 238 | rpiece(); | 
| 239 | exit(cleanup(0)); | 
| 240 | } | 
| 241 |  | 
| 242 |  | 
| 243 | static void | 
| 244 | dolock(         /* lock or unlock a file */ | 
| 245 | int  fd, | 
| 246 | int  ltyp | 
| 247 | ) | 
| 248 | { | 
| 249 | static struct flock  fls;       /* static so initialized to zeroes */ | 
| 250 |  | 
| 251 | fls.l_type = ltyp; | 
| 252 | if (fcntl(fd, F_SETLKW, &fls) < 0) { | 
| 253 | fprintf(stderr, "%s: cannot lock/unlock file: %s\n", | 
| 254 | progname, strerror(errno)); | 
| 255 | _exit(1); | 
| 256 | } | 
| 257 | } | 
| 258 |  | 
| 259 |  | 
| 260 | static void | 
| 261 | init(                   /* set up output file and start rpict */ | 
| 262 | int  ac, | 
| 263 | char  **av | 
| 264 | ) | 
| 265 | { | 
| 266 | static char  hrbuf[16], vrbuf[16]; | 
| 267 | extern char  VersionID[]; | 
| 268 | char  *err; | 
| 269 | FILE  *fp; | 
| 270 | int  hr, vr; | 
| 271 | SUBPROC  rpd; /* since we don't close_process(), this can be local */ | 
| 272 | /* set up view */ | 
| 273 | if ((err = setview(&ourview)) != NULL) { | 
| 274 | fprintf(stderr, "%s: %s\n", progname, err); | 
| 275 | exit(1); | 
| 276 | } | 
| 277 | if (syncfp != NULL) { | 
| 278 | sflock(F_RDLCK); | 
| 279 | fscanf(syncfp, "%d %d", &hmult, &vmult); | 
| 280 | sflock(F_UNLCK); | 
| 281 | } | 
| 282 | /* compute piece size */ | 
| 283 | hr = hres; vr = vres; | 
| 284 | if (pixaspect > FTINY) | 
| 285 | normaspect(viewaspect(&ourview), &pixaspect, &hr, &vr); | 
| 286 | hres /= hmult; | 
| 287 | vres /= vmult; | 
| 288 | if (hres <= 0 || vres <= 0) { | 
| 289 | fprintf(stderr, "%s: illegal resolution/subdivision\n", progname); | 
| 290 | exit(1); | 
| 291 | } | 
| 292 | normaspect(viewaspect(&ourview)*hmult/vmult, &pixaspect, &hres, &vres); | 
| 293 | if (!nowarn && (hr != hres*hmult) | (vr != vres*vmult)) | 
| 294 | fprintf(stderr, | 
| 295 | "%s: warning - changed resolution from %dx%d to %dx%d\n", | 
| 296 | progname, hr, vr, hres*hmult, vres*vmult); | 
| 297 | sprintf(hrbuf, "%d", hres); | 
| 298 | rpargv[rpargc++] = "-x"; rpargv[rpargc++] = hrbuf; | 
| 299 | sprintf(vrbuf, "%d", vres); | 
| 300 | rpargv[rpargc++] = "-y"; rpargv[rpargc++] = vrbuf; | 
| 301 | rpargv[rpargc++] = "-pa"; rpargv[rpargc++] = "0"; | 
| 302 | rpargv[rpargc++] = "-pm"; rpargv[rpargc++] = "0"; | 
| 303 | rpargv[rpargc++] = av[ac-1]; | 
| 304 | rpargv[rpargc] = NULL; | 
| 305 | /* open output file */ | 
| 306 | if ((outfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0666)) >= 0) { | 
| 307 | dolock(outfd, F_WRLCK); | 
| 308 | if ((fp = fdopen(dup(outfd), "w")) == NULL) | 
| 309 | goto filerr; | 
| 310 | newheader("RADIANCE", fp);      /* create header */ | 
| 311 | printargs(ac, av, fp); | 
| 312 | fprintf(fp, "SOFTWARE= %s\n", VersionID); | 
| 313 | fprintf(fp, "TILED= %d %d\n", hmult, vmult); | 
| 314 | fputs(VIEWSTR, fp); | 
| 315 | fprintview(&ourview, fp); | 
| 316 | fputc('\n', fp); | 
| 317 | fputnow(fp); | 
| 318 | if ((pixaspect < .995) | (pixaspect > 1.005)) | 
| 319 | fputaspect(pixaspect, fp); | 
| 320 | fputprims(stdprims, fp); | 
| 321 | fputformat(COLRFMT, fp); | 
| 322 | fputc('\n', fp); | 
| 323 | fprtresolu(hres*hmult, vres*vmult, fp); | 
| 324 | } else if ((outfd = open(outfile, O_RDWR)) >= 0) { | 
| 325 | dolock(outfd, F_RDLCK); | 
| 326 | if ((fp = fdopen(dup(outfd), "r+")) == NULL) | 
| 327 | goto filerr; | 
| 328 | getheader(fp, NULL, NULL);      /* skip header */ | 
| 329 | if (!fscnresolu(&hr, &vr, fp) ||        /* check resolution */ | 
| 330 | hr != hres*hmult || vr != vres*vmult) { | 
| 331 | fprintf(stderr, "%s: resolution mismatch on file \"%s\"\n", | 
| 332 | progname, outfile); | 
| 333 | exit(1); | 
| 334 | } | 
| 335 | } else { | 
| 336 | fprintf(stderr, "%s: cannot open file \"%s\"\n", | 
| 337 | progname, outfile); | 
| 338 | exit(1); | 
| 339 | } | 
| 340 | scanorig = ftell(fp);           /* record position of first scanline */ | 
| 341 | if (fclose(fp) == -1)           /* done with stream i/o */ | 
| 342 | goto filerr; | 
| 343 | dolock(outfd, F_UNLCK); | 
| 344 | /* start rpict process */ | 
| 345 | rpd = sp_inactive; | 
| 346 | if (open_process(&rpd, rpargv) <= 0) { | 
| 347 | fprintf(stderr, "%s: cannot start %s\n", progname, rpargv[0]); | 
| 348 | exit(1); | 
| 349 | } | 
| 350 | if ((fromrp = fdopen(rpd.r, "r")) == NULL || | 
| 351 | (torp = fdopen(rpd.w, "w")) == NULL) { | 
| 352 | fprintf(stderr, "%s: cannot open stream to %s\n", | 
| 353 | progname, rpargv[0]); | 
| 354 | exit(1); | 
| 355 | } | 
| 356 | if ((pbuf = (COLR *)bmalloc(hres*vres*sizeof(COLR))) == NULL) { | 
| 357 | fprintf(stderr, "%s: out of memory\n", progname); | 
| 358 | exit(1); | 
| 359 | } | 
| 360 | signal(SIGALRM, onalrm); | 
| 361 | if (timelim) | 
| 362 | alarm(timelim); | 
| 363 | return; | 
| 364 | filerr: | 
| 365 | fprintf(stderr, "%s: i/o error on file \"%s\"\n", progname, outfile); | 
| 366 | exit(1); | 
| 367 | } | 
| 368 |  | 
| 369 |  | 
| 370 | static int | 
| 371 | nextpiece(              /* get next piece assignment */ | 
| 372 | int     *xp, | 
| 373 | int     *yp | 
| 374 | ) | 
| 375 | { | 
| 376 | if (gotalrm)                    /* someone wants us to quit */ | 
| 377 | return(0); | 
| 378 | if (syncfp != NULL) {           /* use sync file */ | 
| 379 | /* | 
| 380 | * So we don't necessarily have to lock and unlock the file | 
| 381 | * multiple times (very slow), we establish an exclusive | 
| 382 | * lock at the beginning on our synchronization file and | 
| 383 | * maintain it in the subroutine rvrpiece(). | 
| 384 | */ | 
| 385 | sflock(F_WRLCK); | 
| 386 | fseek(syncfp, 0L, 0);           /* read position */ | 
| 387 | if (fscanf(syncfp, "%*d %*d %d %d", xp, yp) < 2) { | 
| 388 | *xp = hmult-1; | 
| 389 | *yp = vmult; | 
| 390 | } | 
| 391 | if (rvrlim == 0)                /* initialize recovery limit */ | 
| 392 | rvrlim = *xp*vmult + *yp; | 
| 393 | if (rvrpiece(xp, yp)) {         /* do stragglers first */ | 
| 394 | sflock(F_UNLCK); | 
| 395 | return(1); | 
| 396 | } | 
| 397 | if (--(*yp) < 0) {              /* decrement position */ | 
| 398 | *yp = vmult-1; | 
| 399 | if (--(*xp) < 0) {      /* all done */ | 
| 400 | sflock(F_UNLCK); | 
| 401 | return(0); | 
| 402 | } | 
| 403 | } | 
| 404 | fseek(syncfp, 0L, 0);           /* write new position */ | 
| 405 | fprintf(syncfp, "%4d %4d\n%4d %4d\n\n", hmult, vmult, *xp, *yp); | 
| 406 | fflush(syncfp); | 
| 407 | sflock(F_UNLCK);                /* release sync file */ | 
| 408 | return(1); | 
| 409 | } | 
| 410 | return(scanf("%d %d", xp, yp) == 2);    /* use stdin */ | 
| 411 | } | 
| 412 |  | 
| 413 |  | 
| 414 | static int | 
| 415 | rvrpiece(               /* check for recoverable pieces */ | 
| 416 | int     *xp, | 
| 417 | int     *yp | 
| 418 | ) | 
| 419 | { | 
| 420 | static char  *pdone = NULL;     /* which pieces are done */ | 
| 421 | static long  readpos = -1;      /* how far we've read */ | 
| 422 | int  px, py, i; | 
| 423 | /* | 
| 424 | * This routine is called by nextpiece() with an | 
| 425 | * exclusive lock on syncfp and the file pointer at the | 
| 426 | * appropriate position to read in the finished pieces. | 
| 427 | */ | 
| 428 | if (rvrlim < 0) | 
| 429 | return(0);              /* only check if asked */ | 
| 430 | if (pdone == NULL)              /* first call */ | 
| 431 | pdone = (char *)calloc(hmult*vmult, sizeof(char)); | 
| 432 | if (pdone == NULL) { | 
| 433 | fprintf(stderr, "%s: out of memory\n", progname); | 
| 434 | exit(1); | 
| 435 | } | 
| 436 | if (readpos != -1)              /* mark what's been done */ | 
| 437 | fseek(syncfp, readpos, 0); | 
| 438 | while (fscanf(syncfp, "%d %d", &px, &py) == 2) | 
| 439 | pdone[px*vmult+py] = 1; | 
| 440 | if (!feof(syncfp)) { | 
| 441 | fprintf(stderr, "%s: format error in sync file\n", progname); | 
| 442 | exit(1); | 
| 443 | } | 
| 444 | readpos = ftell(syncfp); | 
| 445 | i = hmult*vmult;                /* find an unaccounted for piece */ | 
| 446 | while (i-- > rvrlim) | 
| 447 | if (!pdone[i]) { | 
| 448 | *xp = i / vmult; | 
| 449 | *yp = i % vmult; | 
| 450 | pdone[i] = 1;   /* consider it done */ | 
| 451 | return(1); | 
| 452 | } | 
| 453 | rvrlim = -1;                    /* nothing left to recover */ | 
| 454 | free(pdone); | 
| 455 | pdone = NULL; | 
| 456 | return(0); | 
| 457 | } | 
| 458 |  | 
| 459 |  | 
| 460 | static int | 
| 461 | cleanup(                        /* close rpict process and clean up */ | 
| 462 | int  rstat | 
| 463 | ) | 
| 464 | { | 
| 465 | int  status; | 
| 466 |  | 
| 467 | bfree((char *)pbuf, hres*vres*sizeof(COLR)); | 
| 468 | fclose(torp); | 
| 469 | fclose(fromrp); | 
| 470 | while (wait(&status) != -1) | 
| 471 | if (rstat == 0) | 
| 472 | rstat = status>>8 & 0xff; | 
| 473 | return(rstat); | 
| 474 | } | 
| 475 |  | 
| 476 |  | 
| 477 | static void | 
| 478 | rpiece(void)                    /* render picture piece by piece */ | 
| 479 | { | 
| 480 | char  *err; | 
| 481 | VIEW  pview; | 
| 482 | int  xorg, yorg; | 
| 483 | /* render each piece */ | 
| 484 | while (nextpiece(&xorg, &yorg)) { | 
| 485 | pview = ourview; | 
| 486 | err = cropview(&pview, (double)xorg/hmult, (double)yorg/vmult, | 
| 487 | (xorg+1.)/hmult, (yorg+1.)/vmult); | 
| 488 | if (err != NULL) { | 
| 489 | fprintf(stderr, "%s: %s\n", progname, err); | 
| 490 | exit(cleanup(1)); | 
| 491 | } | 
| 492 | fputs(VIEWSTR, torp); | 
| 493 | fprintview(&pview, torp); | 
| 494 | fputc('\n', torp); | 
| 495 | fflush(torp);                   /* assigns piece to rpict */ | 
| 496 | putpiece(xorg, yorg);           /* place piece in output */ | 
| 497 | } | 
| 498 | } | 
| 499 |  | 
| 500 |  | 
| 501 | static int | 
| 502 | putpiece(               /* get next piece from rpict */ | 
| 503 | int     xpos, | 
| 504 | int     ypos | 
| 505 | ) | 
| 506 | { | 
| 507 | struct flock  fls; | 
| 508 | int  pid, status; | 
| 509 | int  hr, vr; | 
| 510 | int  y; | 
| 511 | /* check bounds */ | 
| 512 | if ((xpos < 0) | (ypos < 0) | (xpos >= hmult) | (ypos >= vmult)) { | 
| 513 | fprintf(stderr, "%s: requested piece (%d,%d) out of range\n", | 
| 514 | progname, xpos, ypos); | 
| 515 | exit(cleanup(1)); | 
| 516 | } | 
| 517 | /* check header from rpict */ | 
| 518 | guard_io(); | 
| 519 | getheader(fromrp, NULL, NULL); | 
| 520 | if (!fscnresolu(&hr, &vr, fromrp) || (hr != hres) | (vr != vres)) { | 
| 521 | fprintf(stderr, "%s: resolution mismatch from %s\n", | 
| 522 | progname, rpargv[0]); | 
| 523 | exit(cleanup(1)); | 
| 524 | } | 
| 525 | if (verbose) {                          /* notify caller */ | 
| 526 | printf("%d %d begun\n", xpos, ypos); | 
| 527 | fflush(stdout); | 
| 528 | } | 
| 529 | unguard(); | 
| 530 | /* load new piece into buffer */ | 
| 531 | for (y = 0; y < vr; y++) { | 
| 532 | guard_io(); | 
| 533 | if (freadcolrs(pbuf+y*hr, hr, fromrp) < 0) { | 
| 534 | fprintf(stderr, "%s: read error from %s\n", | 
| 535 | progname, rpargv[0]); | 
| 536 | exit(cleanup(1)); | 
| 537 | } | 
| 538 | unguard(); | 
| 539 | } | 
| 540 | #if MAXFORK | 
| 541 | /* fork so we don't slow rpict down */ | 
| 542 | if ((pid = fork()) > 0) { | 
| 543 | if (++nforked >= MAXFORK) { | 
| 544 | wait(&status);          /* reap a child */ | 
| 545 | if (status) | 
| 546 | exit(cleanup(status>>8 & 0xff)); | 
| 547 | nforked--; | 
| 548 | } | 
| 549 | return(pid); | 
| 550 | } | 
| 551 | #else | 
| 552 | pid = -1;               /* no forking */ | 
| 553 | #endif | 
| 554 | fls.l_start = scanorig + | 
| 555 | ((long)(vmult-1-ypos)*vres*hmult+xpos)*hres*sizeof(COLR); | 
| 556 | #if NFS | 
| 557 | fls.l_len = ((long)(vres-1)*hmult+1)*hres*sizeof(COLR); | 
| 558 | /* lock file section so NFS doesn't mess up */ | 
| 559 | fls.l_whence = 0; | 
| 560 | fls.l_type = F_WRLCK; | 
| 561 | #if 0 | 
| 562 | if (fcntl(outfd, F_SETLKW, &fls) < 0) | 
| 563 | filerr("lock"); | 
| 564 | #else | 
| 565 | dolock(outfd, F_WRLCK); | 
| 566 | #endif | 
| 567 | #endif | 
| 568 | /* write new piece to file */ | 
| 569 | if (lseek(outfd, (off_t)fls.l_start, SEEK_SET) < 0) | 
| 570 | filerr("seek"); | 
| 571 | if (hmult == 1) { | 
| 572 | if (writebuf(outfd, pbuf, | 
| 573 | vr*hr*sizeof(COLR)) != vr*hr*sizeof(COLR)) | 
| 574 | filerr("write"); | 
| 575 | } else | 
| 576 | for (y = 0; y < vr; y++) { | 
| 577 | if (writebuf(outfd, pbuf+y*hr, | 
| 578 | hr*sizeof(COLR)) != hr*sizeof(COLR)) | 
| 579 | filerr("write"); | 
| 580 | if (y < vr-1 && lseek(outfd, | 
| 581 | (off_t)(hmult-1)*hr*sizeof(COLR), | 
| 582 | SEEK_CUR) < 0) | 
| 583 | filerr("seek"); | 
| 584 | } | 
| 585 | #if NFS | 
| 586 | fls.l_type = F_UNLCK;           /* release lock */ | 
| 587 | #if 0 | 
| 588 | if (fcntl(outfd, F_SETLKW, &fls) < 0) | 
| 589 | filerr("lock"); | 
| 590 | #else | 
| 591 | dolock(outfd, F_UNLCK); | 
| 592 | #endif | 
| 593 | #endif | 
| 594 | if (verbose) {                          /* notify caller */ | 
| 595 | printf("%d %d done\n", xpos, ypos); | 
| 596 | fflush(stdout); | 
| 597 | } | 
| 598 | if (syncfp != NULL) {                   /* record what's been done */ | 
| 599 | sflock(F_WRLCK); | 
| 600 | fseek(syncfp, 0L, 2);           /* append index */ | 
| 601 | fprintf(syncfp, "%4d %4d\n", xpos, ypos); | 
| 602 | fflush(syncfp); | 
| 603 | /*** Unlock not necessary, since | 
| 604 | sflock(F_UNLCK);        _exit() or nextpiece() is next ***/ | 
| 605 | } | 
| 606 | if (pid == -1)          /* didn't fork or fork failed */ | 
| 607 | return(0); | 
| 608 | _exit(0);               /* else exit child process (releasing locks) */ | 
| 609 | } | 
| 610 |  | 
| 611 |  | 
| 612 | static void | 
| 613 | filerr(                 /* report file error and exit */ | 
| 614 | char  *t | 
| 615 | ) | 
| 616 | { | 
| 617 | fprintf(stderr, "%s: %s error on file \"%s\": %s\n", | 
| 618 | progname, t, outfile, strerror(errno)); | 
| 619 | _exit(1); | 
| 620 | } | 
| 621 |  | 
| 622 | #endif |