backport to buster
[hcoop/debian/openafs.git] / src / util / exec.c
CommitLineData
805e021f
CE
1/*
2 * Copyright 2010, Sine Nomine Associates and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10/* exec-related helper routines */
11
12#include <afsconfig.h>
13#include <afs/param.h>
14
15#include <roken.h>
16
17/* helper for afs_exec_alt; just constructs the string for the 'alternate'
18 * program */
19static char *
20construct_alt(const char *argv0, const char *prefix, const char *suffix)
21{
22 size_t prefix_len = strlen(prefix);
23 size_t suffix_len = strlen(suffix);
24 size_t replace_len;
25 char *alt, *replace;
26
27 alt = malloc(strlen(argv0) + prefix_len + suffix_len + 1);
28 if (!alt) {
29 return NULL;
30 }
31 strcpy(alt, argv0);
32
33 replace = strrchr(alt, '/');
34 if (replace) {
35 replace++;
36 } else {
37 replace = alt;
38 }
39
40 replace_len = strlen(replace);
41
42 memmove(replace + prefix_len, replace, replace_len);
43 memcpy(replace, prefix, prefix_len);
44 /* basically strcat(replace, suffix), but a touch faster */
45 memcpy(replace + prefix_len + replace_len, suffix, suffix_len + 1);
46
47 return alt;
48}
49
50/**
51 * execute an alternate version of the running program.
52 *
53 * This takes the current argc/argv, and executes an "anternate" version
54 * of the current program ("alternate" meaning e.g. DAFS/non-DAFS,
55 * 32-bit/64-bit, etc). For example, if the current running program is
56 * fssync-debug, running afs_exec_alt(argc, argc, "da", NULL) will try
57 * to execute a "dafssync-debug" program, if it can be run.
58 *
59 * @param[in] argc argc for the current program
60 * @param[in] argv argv for the current program
61 * @param[in] prefix prefix for the alternate program (or NULL)
62 * @param[in] suffix suffix for the alternate program (or NULL)
63 *
64 * @return the program that we failed to run, or NULL if we failed
65 * before constructing it. This string must be freed by the caller
66 *
67 * @pre at least one of 'prefix' or 'suffix' is non-NULL and non-empty
68 *
69 * @note if successful, never returns
70 */
71char *
72afs_exec_alt(int argc, char **argv, const char *prefix, const char *suffix)
73{
74 char **targv = NULL;
75 char *ret = NULL;
76 int errno_save;
77 int i = 0;
78
79 if (!prefix) {
80 prefix = "";
81 }
82 if (!suffix) {
83 suffix = "";
84 }
85
86 if (prefix[0] == '\0' && suffix[0] == '\0') {
87 /* we'd be exec'ing ourselves; that's no good */
88 errno = EINVAL;
89 return NULL;
90 }
91
92 targv = malloc(sizeof(char*) * (argc+1));
93 if (!targv) {
94 goto error;
95 }
96
97 targv[0] = construct_alt(argv[0], prefix, suffix);
98 if (!targv[0]) {
99 goto error;
100 }
101
102 for (i = 1; i < argc; i++) {
103 targv[i] = strdup(argv[i]);
104 if (!targv[i]) {
105 goto error;
106 }
107 }
108 targv[i] = NULL;
109
110 execvp(targv[0], targv);
111
112 error:
113 /* we only call free() beyond this point, which I don't think would ever
114 * muck with errno, but I don't trust everyone's libc... */
115 errno_save = errno;
116 if (targv) {
117 i--;
118 for (; i >= 1; i--) {
119 free(targv[i]);
120 }
121 ret = targv[0];
122 free(targv);
123 }
124 errno = errno_save;
125 return ret;
126}