Print this page
8485 Remove set but unused variables in usr/src/cmd
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svr4pkg/pkgremove/special.c
+++ new/usr/src/cmd/svr4pkg/pkgremove/special.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 + * Copyright 2017 Gary Mills
23 24 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 25 * Use is subject to license terms.
25 26 */
26 27
27 28
28 29 /*
29 30 * special.c
30 31 *
31 32 * This module contains code required to remove special contents from
32 33 * the contents file when a pkgrm is done on a system upgraded to use
33 34 * the new database.
34 35 */
35 36
36 37 #include <stdio.h>
37 38 #include <stdlib.h>
38 39 #include <assert.h>
39 40 #include <errno.h>
40 41 #include <unistd.h>
41 42 #include <string.h>
42 43 #include <time.h>
43 44 #include <limits.h>
44 45 #include <fnmatch.h>
45 46 #include <sys/types.h>
46 47 #include <sys/stat.h>
47 48 #include <pkgstrct.h>
48 49 #include "pkglib.h"
49 50 #include <libintl.h>
50 51
51 52 /* This specifies the maximum length of a contents file line read in. */
52 53 #define LINESZ 8192
53 54
54 55 #define SPECIAL_MALLOC "unable to maintain package contents text due to "\
55 56 "insufficient memory."
56 57 #define SPECIAL_ACCESS "unable to maintain package contents text due to "\
57 58 "an access failure."
58 59 #define SPECIAL_INPUT "unable to maintain package contents text: alternate "\
59 60 "root path too long"
60 61
61 62 /*
62 63 * strcompare
63 64 *
64 65 * This function is used by qsort to sort an array of special contents
65 66 * rule strings. This array must be sorted to facilitate efficient
66 67 * rule processing. See qsort(3c) regarding qsort compare functions.
67 68 */
68 69 static int
69 70 strcompare(const void *pv1, const void *pv2)
70 71 {
71 72 char **ppc1 = (char **) pv1;
72 73 char **ppc2 = (char **) pv2;
73 74 int i = strcmp(*ppc1, *ppc2);
74 75 if (i < 0)
75 76 return (-1);
76 77 if (i > 0)
77 78 return (1);
78 79 return (0);
79 80 }
80 81
81 82 /*
82 83 * match
83 84 *
84 85 * This function determines whether a file name (pc) matches a rule
85 86 * from the special contents file (pcrule). We assume that neither
86 87 * string is ever NULL.
87 88 *
88 89 * Return: 1 on match, 0 on no match.
89 90 * Side effects: none.
90 91 */
91 92 static int
92 93 match(const char *pc, char *pcrule)
93 94 {
94 95 int n = strlen(pcrule);
95 96 int wild = 0;
96 97 if (pcrule[n - 1] == '*') {
97 98 wild = 1;
98 99 pcrule[n - 1] = '\0';
99 100 }
100 101
101 102 if (!wild) {
102 103 if (fnmatch(pc, pcrule, FNM_PATHNAME) == 0 ||
103 104 fnmatch(pc, pcrule, 0) == 0)
104 105 return (1);
105 106 } else {
106 107 int j;
107 108 j = strncmp(pc, pcrule, n - 1);
108 109 pcrule[n - 1] = '*';
109 110 if (j == 0)
110 111 return (1);
111 112 }
112 113 return (0);
113 114 }
114 115
115 116 /*
116 117 * search_special_contents
117 118 *
118 119 * This function assumes that a series of calls will be made requesting
119 120 * whether a given path matches the special contents rules or not. We
120 121 * assume that
121 122 *
122 123 * a) the special_contents array is sorted
123 124 * b) the calls will be made with paths in a sorted order
124 125 *
125 126 * Given that, we can keep track of where the last search ended and
126 127 * begin the new search at that point. This reduces the cost of a
127 128 * special contents matching search to O(n) from O(n^2).
128 129 *
129 130 * ppcSC A pointer to an array of special contents obtained via
130 131 * get_special_contents().
131 132 * path A path: determine whether it matches the special
132 133 * contents rules or not.
133 134 * piX The position in the special_contents array we have already
134 135 * arrived at through searching. This must be initialized to
135 136 * zero before initiating a series of search_special_contents
136 137 * operations.
137 138 *
138 139 * Example:
139 140 * {
140 141 * int i = 0, j, max;
141 142 * char **ppSC = NULL;
142 143 * if (get_special_contents(NULL, &ppcSC, &max) != 0) exit(1);
143 144 * for (j = 0; paths != NULL && paths[j] != NULL; j++) {
144 145 * if (search_special_contents(ppcSC, path[j], &i)) {
145 146 * do_something_with_special_path(path[j]);
146 147 * }
147 148 * }
148 149 * }
149 150 *
150 151 * Return: 1 if there is a match, 0 otherwise.
151 152 * Side effects: The value of *piX will be set between calls to this
152 153 * function. To make this function thread safe, use search arrays.
153 154 * Also: Nonmatching entries are eliminated, set to NULL.
154 155 */
155 156 static int
156 157 search_special_contents(char **ppcSC, const char *pcpath, int *piX, int max)
157 158 {
158 159 int wild;
159 160 if (ppcSC == NULL || *piX == max)
160 161 return (0);
161 162
162 163 while (*piX < max) {
163 164
164 165 int j, k;
165 166 if (ppcSC[*piX] == NULL) {
166 167 (*piX)++;
167 168 continue;
168 169 }
169 170
170 171 j = strlen(ppcSC[*piX]);
171 172 k = strcmp(pcpath, ppcSC[*piX]);
172 173 wild = (ppcSC[*piX][j - 1] == '*');
173 174
174 175 /*
175 176 * Depending on whether the path string compared with the
176 177 * rule, we take different actions. If the path is less
177 178 * than the rule, we keep the rule. If the path equals
178 179 * the rule, we advance the rule (as long as the rule is
179 180 * not a wild card). If the path is greater than the rule,
180 181 * we have to advance the rule list until we are less or equal
181 182 * again. This way we only have to make one pass through the
182 183 * rules, as we make one pass through the path strings. We
183 184 * assume that the rules and the path strings are sorted.
184 185 */
185 186 if (k < 0) {
186 187
187 188 if (wild == 0)
188 189 return (0);
189 190
190 191 if (match(pcpath, ppcSC[*piX]))
191 192 return (1);
192 193 break;
193 194
194 195 } else if (k == 0) {
195 196
196 197 int x = match(pcpath, ppcSC[*piX]);
197 198 if (wild == 0) (*piX)++;
198 199 return (x);
199 200
200 201 } else {
201 202 /* One last try. */
202 203 if (match(pcpath, ppcSC[*piX]))
203 204 return (1);
204 205
205 206 /*
206 207 * As pcpath > ppcSC[*piX] we have passed up this
207 208 * rule - it cannot apply. Therefore, we do not
208 209 * need to retain it. Removing the rule will make
209 210 * subsequent searching more efficient.
210 211 */
211 212 free(ppcSC[*piX]);
212 213 ppcSC[*piX] = NULL;
213 214
214 215 (*piX)++;
215 216 }
216 217 }
217 218 return (0);
218 219 }
219 220
220 221 /*
221 222 * get_special_contents
222 223 *
223 224 * Retrieves the special contents file entries, if they exist. These
224 225 * are sorted. We do not assume the special_contents file is in sorted
225 226 * order.
226 227 *
227 228 * pcroot The root of the install database. If NULL assume '/'.
228 229 * pppcSC A pointer to a char **. This pointer will be set to
229 230 * point at NULL if there is no special_contents file or
230 231 * to a sorted array of strings, NULL terminated, otherwise.
231 232 * piMax The # of entries in the special contents result.
232 233 *
233 234 * Returns: 0 on no error, nonzero on error.
234 235 * Side effects: the pppcSC pointer is set to point at a newly
235 236 * allocated array of pointers to strings.. The caller must
236 237 * free this buffer. The value of *piMax is set to the # of
237 238 * entries in ppcSC.
238 239 */
239 240 static int
240 241 get_special_contents(const char *pcroot, char ***pppcSC, int *piMax)
241 242 {
242 243 int e, i;
243 244 FILE *fp;
244 245 char line[2048];
245 246 char **ppc;
246 247 char *pc = "var/sadm/install/special_contents";
247 248 char path[PATH_MAX];
248 249 struct stat s;
249 250
250 251 /* Initialize the return values. */
251 252 *piMax = 0;
252 253 *pppcSC = NULL;
253 254
254 255 if (pcroot == NULL) {
255 256 pcroot = "/";
256 257 }
257 258
258 259 if (pcroot[strlen(pcroot) - 1] == '/') {
259 260 if (snprintf(path, PATH_MAX, "%s%s", pcroot, pc) >= PATH_MAX) {
260 261 progerr(gettext(SPECIAL_INPUT));
261 262 return (1);
262 263 }
263 264 } else {
264 265 if (snprintf(path, PATH_MAX, "%s/%s", pcroot, pc)
265 266 >= PATH_MAX) {
266 267 progerr(gettext(SPECIAL_INPUT));
267 268 return (1);
268 269 }
269 270 }
270 271
271 272 errno = 0;
272 273 e = stat(path, &s);
273 274 if (e != 0 && errno == ENOENT)
274 275 return (0); /* No special contents file. Do nothing. */
275 276
276 277 if (access(path, R_OK) != 0 || (fp = fopen(path, "r")) == NULL) {
277 278 /* Could not open special contents which exists */
278 279 progerr(gettext(SPECIAL_ACCESS));
279 280 return (1);
280 281 }
281 282
282 283 for (i = 0; fgets(line, 2048, fp) != NULL; i++);
283 284 rewind(fp);
284 285 if ((ppc = (char **) calloc(i + 1, sizeof (char *))) == NULL) {
285 286 progerr(gettext(SPECIAL_MALLOC));
286 287 return (1);
287 288 }
288 289
289 290 for (i = 0; fgets(line, 2048, fp) != NULL; ) {
290 291 int n;
291 292 if (line[0] == '#' || line[0] == ' ' || line[0] == '\n' ||
292 293 line[0] == '\t' || line[0] == '\r')
293 294 continue;
294 295 n = strlen(line);
295 296 if (line[n - 1] == '\n')
296 297 line[n - 1] = '\0';
297 298 ppc[i++] = strdup(line);
298 299 }
299 300
300 301 qsort(ppc, i, sizeof (char *), strcompare);
301 302
302 303 *pppcSC = ppc;
303 304 *piMax = i;
304 305 return (0);
305 306 }
306 307
307 308 /*
308 309 * free_special_contents
309 310 *
310 311 * This function frees special_contents which have been allocated using
311 312 * get_special_contents.
312 313 *
313 314 * pppcSC A pointer to a buffer allocated using get_special_contents.
314 315 * max The number of entries allocated.
315 316 *
316 317 * Result: None.
317 318 * Side effects: Frees memory allocated using get_special_contents and
318 319 * sets the pointer passed in to NULL.
319 320 */
320 321 static void
321 322 free_special_contents(char ***pppcSC, int max)
322 323 {
323 324 int i;
324 325 char **ppc = NULL;
325 326 if (*pppcSC == NULL)
326 327 return;
327 328
328 329 ppc = *pppcSC;
329 330 for (i = 0; ppc != NULL && i < max; i++)
330 331 if (ppc[i] == NULL)
331 332 free(ppc[i]);
332 333
333 334 if (ppc != NULL)
334 335 free(ppc);
335 336
336 337 *pppcSC = NULL;
337 338 }
338 339
339 340 /*
340 341 * get_path
341 342 *
342 343 * Return the first field of a string delimited by a space.
343 344 *
344 345 * pcline A line from the contents file.
345 346 *
346 347 * Return: NULL if an error. Otherwise a string allocated by this
347 348 * function. The caller must free the string.
348 349 * Side effects: none.
349 350 */
350 351 static char *
351 352 get_path(const char *pcline)
352 353 {
353 354 int i = strcspn(pcline, " ");
354 355 char *pc = NULL;
355 356 if (i <= 1 || (pc = (char *) calloc(i + 1, 1)) == NULL)
356 357 return (NULL);
357 358 (void) memcpy(pc, pcline, i);
358 359 return (pc);
359 360 }
360 361
361 362 /*
362 363 * generate_special_contents_rules
363 364 *
364 365 * This procedure will generate an array of integers which will be a mask
365 366 * to apply to the ppcfextra array. If set to 1, then the content must be
366 367 * added to the contents file. Otherwise it will not be: The old contents
367 368 * file will be used for this path value, if one even exists.
368 369 *
369 370 * ient The number of ppcfextra contents installed.
370 371 * ppcfent The contents installed.
371 372 * ppcSC The rules (special contents)
372 373 * max The number of special contents rules.
373 374 * ppiIndex The array of integer values, determining whether
374 375 * individual ppcfextra items match special contents rules.
375 376 * This array will be created and set in this function and
376 377 * returned.
377 378 *
378 379 * Return: 0 success, nonzero failure
379 380 * Side effects: allocates an array of integers that the caller must free.
380 381 */
381 382 static int
382 383 generate_special_contents_rules(int ient, struct cfent **ppcfent,
383 384 char **ppcSC, int max, int **ppiIndex)
384 385 {
385 386 int i, j;
386 387 int *pi = (int *) calloc(ient, sizeof (int));
387 388 if (pi == NULL) {
388 389 progerr(gettext(SPECIAL_MALLOC));
389 390 return (1);
390 391 }
391 392
392 393 /*
393 394 * For each entry in ppcfextra, check if it matches a rule.
394 395 * If it does not, set the entry in the index to -1.
395 396 */
396 397 for (i = 0, j = 0; i < ient && j < max; i++) {
397 398 if (search_special_contents(ppcSC, ppcfent[i]->path,
398 399 &j, max) == 1) {
399 400 pi[i] = 1;
400 401
401 402 } else {
402 403 pi[i] = 0;
403 404 }
404 405 }
405 406
406 407 /*
407 408 * In case we ran out of rules before contents, we will not use
408 409 * those contents. Make sure these contents are set to 0 and
409 410 * will not be copied from the ppcfent array into the contents
410 411 * file.
411 412 */
412 413 for (i = i; i < ient; i++)
413 414 pi[i] = 0;
414 415
415 416 *ppiIndex = pi;
416 417 return (0);
417 418 }
418 419
419 420
420 421 /*
421 422 * pathcmp
422 423 *
423 424 * Compare a path to a cfent. It will match either if the path is
424 425 * equal to the cfent path, or if the cfent is a symbolic or link
425 426 * and *that* matches.
426 427 *
427 428 * path a path
428 429 * pent a contents entry
429 430 *
430 431 * Returns: as per strcmp
431 432 * Side effects: none.
432 433 */
433 434 static int
434 435 pathcmp(const char *pc, const struct cfent *pent)
435 436 {
436 437 int i;
437 438 if ((pent->ftype == 's' || pent->ftype == 'l') &&
438 439 pent->ainfo.local) {
439 440 char *p, *q;
440 441 if ((p = strstr(pc, "=")) == NULL) {
441 442
442 443 i = strcmp(pc, pent->path);
443 444
444 445 /* A path without additional chars strcmp's to less */
445 446 if (i == 0)
446 447 i = -1;
447 448
448 449 } else {
449 450 /* Break the link path into two pieces. */
450 451 *p = '\0';
451 452
452 453 /* Compare the first piece. */
453 454 i = strcmp(pc, pent->path);
454 455
455 456 /* If equal we must compare the second piece. */
456 457 if (i == 0) {
457 458 q = p + 1;
458 459 i = strcmp(q, pent->ainfo.local);
459 460 }
460 461
461 462 /* Restore the link path. */
462 463 *p = '=';
463 464 }
464 465 } else {
465 466 i = strcmp(pc, pent->path);
466 467 }
467 468
468 469 return (i);
469 470 }
470 471
471 472 /*
472 473 * -----------------------------------------------------------------------
473 474 * Externally visible function.
474 475 */
475 476
476 477 /*
477 478 * special_contents_remove
478 479 *
479 480 * Given a set of entries to remove and an alternate root, this function
480 481 * will do everything required to ensure that the entries are removed
481 482 * from the contents file if they are listed in the special_contents
482 483 * file. The contents file will get changed only in the case that the
483 484 * entire operation has succeeded.
484 485 *
485 486 * ient The number of entries.
486 487 * ppcfent The entries to remove.
487 488 * pcroot The alternate install root. Could be NULL. In this
488 489 * case, assume root is '/'
489 490 *
490 491 * Result: 0 on success, nonzero on failure. If an error occurs, an
491 492 * error string will get output to standard error alerting the user.
↓ open down ↓ |
459 lines elided |
↑ open up ↑ |
492 493 * Side effects: The contents file may change as a result of this call,
493 494 * such that lines in the in the file will be changed or removed.
494 495 * If the call fails, a t.contents file may be left behind. This
495 496 * temporary file should be removed subsequently.
496 497 */
497 498 int
498 499 special_contents_remove(int ient, struct cfent **ppcfent, const char *pcroot)
499 500 {
500 501 int result = 0; /* Assume we will succeed. Return result. */
501 502 char **ppcSC = NULL; /* The special contents rules, sorted. */
502 - int i, j; /* Indexes into contents & special contents */
503 + int i; /* Index into contents & special contents */
503 504 FILE *fpi = NULL, /* Input of contents file */
504 505 *fpo = NULL; /* Output to temp contents file */
505 506 char cpath[PATH_MAX], /* Contents file path */
506 507 tcpath[PATH_MAX]; /* Temp contents file path */
507 508 const char *pccontents = "var/sadm/install/contents";
508 509 const char *pctcontents = "var/sadm/install/t.contents";
509 510 char line[LINESZ]; /* Reads in and writes out contents lines. */
510 511 time_t t; /* Used to create a timestamp comment. */
511 512 int max; /* Max number of special contents entries. */
512 513 int *piIndex; /* An index to ppcfents to remove from cfile */
513 514
514 515 cpath[0] = tcpath[0] = '\0';
515 516
516 517 if (ient == 0 || ppcfent == NULL || ppcfent[0] == NULL) {
517 518 goto remove_done;
518 519 }
519 520
520 521 if ((get_special_contents(pcroot, &ppcSC, &max)) != 0) {
521 522 result = 1;
522 523 goto remove_done;
523 524 }
524 525
525 526 /* Check if there are no special contents actions to take. */
526 527 if (ppcSC == NULL) {
527 528 goto remove_done;
528 529 }
529 530
530 531 if (pcroot == NULL) pcroot = "/";
531 532 if (pcroot[strlen(pcroot) - 1] == '/') {
532 533 if (snprintf(cpath, PATH_MAX, "%s%s", pcroot, pccontents)
533 534 >= PATH_MAX ||
534 535 snprintf(tcpath, PATH_MAX, "%s%s", pcroot, pctcontents)
535 536 >= PATH_MAX) {
536 537 progerr(gettext(SPECIAL_INPUT));
537 538 result = -1;
538 539 goto remove_done;
539 540 }
540 541 } else {
541 542 if (snprintf(cpath, PATH_MAX, "%s/%s", pcroot, pccontents)
542 543 >= PATH_MAX ||
543 544 snprintf(tcpath, PATH_MAX, "%s/%s", pcroot, pctcontents)
544 545 >= PATH_MAX) {
545 546 progerr(gettext(SPECIAL_INPUT));
546 547 result = -1;
547 548 goto remove_done;
548 549 }
549 550 }
550 551
551 552 /* Open the temporary contents file to write, contents to read. */
552 553 if (access(cpath, F_OK | R_OK) != 0) {
553 554 /*
554 555 * This is not a problem since no contents means nothing
555 556 * to remove due to special contents rules.
556 557 */
557 558 result = 0;
558 559 cpath[0] = '\0'; /* This signals omission of 'rename cleanup' */
559 560 goto remove_done;
560 561 }
561 562
562 563 if (access(cpath, W_OK) != 0) {
563 564 /* can't write contents file, something is wrong. */
564 565 progerr(gettext(SPECIAL_ACCESS));
565 566 result = 1;
566 567 goto remove_done;
567 568
568 569 }
569 570
570 571 if ((fpi = fopen(cpath, "r")) == NULL) {
571 572 /* Given the access test above, this should not happen. */
572 573 progerr(gettext(SPECIAL_ACCESS));
573 574 result = 1;
574 575 goto remove_done;
575 576 }
576 577
577 578 if ((fpo = fopen(tcpath, "w")) == NULL) {
578 579 /* open t.contents failed */
579 580 progerr(gettext(SPECIAL_ACCESS));
580 581 result = 1;
581 582 goto remove_done;
582 583 }
583 584
584 585 if (generate_special_contents_rules(ient, ppcfent, ppcSC, max, &piIndex)
585 586 != 0) {
586 587 result = 1;
587 588 goto remove_done;
588 589 }
589 590
590 591 /*
591 592 * Copy contents to t.contents unless there is an entry in
↓ open down ↓ |
79 lines elided |
↑ open up ↑ |
592 593 * the ppcfent array which corresponds to an index set to 1.
593 594 *
594 595 * These items are the removed package contents which matche an
595 596 * entry in ppcSC (the special_contents rules).
596 597 *
597 598 * Since both the contents and rules are sorted, we can
598 599 * make a single efficient pass.
599 600 */
600 601 (void) memset(line, 0, LINESZ);
601 602
602 - for (i = 0, j = 0; fgets(line, LINESZ, fpi) != NULL; ) {
603 + for (i = 0; fgets(line, LINESZ, fpi) != NULL; ) {
603 604
604 605 char *pcpath = NULL;
605 606
606 607 /*
607 608 * Note: This could be done better: We should figure out
608 609 * which are the last 2 lines and only trim those off.
609 610 * This will suffice to do this and will only be done as
610 611 * part of special_contents handling.
611 612 */
612 613 if (line[0] == '#')
613 614 continue; /* Do not copy the final 2 comment lines */
614 615
615 616 pcpath = get_path(line);
616 617
617 618 if (pcpath != NULL && i < ient) {
618 619 int k;
619 620 while (piIndex[i] == 0)
620 621 i++;
621 622
622 623 if (i < ient)
623 624 k = pathcmp(pcpath, ppcfent[i]);
624 625
625 626 if (k < 0 || i >= ient) {
626 627 /* Just copy contents -> t.contents */
627 628 /*EMPTY*/
628 629 } else if (k == 0) {
629 630 /* We have a match. Do not copy the content. */
630 631 i++;
631 632 free(pcpath);
632 633 (void) memset(line, 0, LINESZ);
633 634 continue;
634 635 } else while (i < ient) {
635 636
636 637 /*
637 638 * This is a complex case: The content
638 639 * entry is further along alphabetically
639 640 * than the rule. Skip over all rules which
640 641 * apply until we come to a rule which is
641 642 * greater than the current entry, or equal
642 643 * to it. If equal, do not copy, otherwise
643 644 * do copy the entry.
644 645 */
645 646 if (piIndex[i] == 0) {
646 647 i++;
647 648 continue;
648 649 } else if ((k = pathcmp(pcpath, ppcfent[i]))
649 650 >= 0) {
650 651 i++;
651 652 if (k == 0) {
652 653 free(pcpath);
653 654 (void) memset(line, 0, LINESZ);
654 655 break;
655 656 }
656 657 } else {
657 658 /* path < rule, end special case */
658 659 break;
659 660 }
660 661 }
661 662
662 663 /*
663 664 * Avoid copying the old content when path == rule
664 665 * This occurs when the complex case ends on a match.
665 666 */
666 667 if (k == 0)
667 668 continue;
668 669 }
669 670
670 671 if (fprintf(fpo, "%s", line) < 0) {
671 672 /* Failing to write output would be catastrophic. */
672 673 progerr(gettext(SPECIAL_ACCESS));
673 674 result = 1;
674 675 break;
675 676 }
676 677 (void) memset(line, 0, LINESZ);
677 678 }
678 679
679 680 t = time(NULL);
680 681 (void) fprintf(fpo, "# Last modified by pkgremove\n");
681 682 (void) fprintf(fpo, "# %s", ctime(&t));
682 683
683 684 remove_done:
684 685 free_special_contents(&ppcSC, max);
685 686
686 687 if (fpi != NULL)
687 688 (void) fclose(fpi);
688 689
689 690 if (fpo != NULL)
690 691 (void) fclose(fpo);
691 692
692 693 if (result == 0) {
693 694 if (tcpath[0] != '\0' && cpath[0] != '\0' &&
694 695 rename(tcpath, cpath) != 0) {
695 696 progerr(gettext(SPECIAL_ACCESS));
696 697 result = 1;
697 698 }
698 699 } else {
699 700 if (tcpath[0] != '\0' && remove(tcpath) != 0) {
700 701 /*
701 702 * Do not output a diagnostic message. This condition
702 703 * occurs only when we are unable to clean up after
703 704 * a failure. A temporary file will linger.
704 705 */
705 706 result = 1;
706 707 }
707 708 }
708 709
709 710 return (result);
710 711 }
↓ open down ↓ |
98 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX