1/*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "misc"
18
19//
20// Miscellaneous utility functions.
21//
22#include <utils/misc.h>
23#include <utils/Log.h>
24
25#include <sys/stat.h>
26#include <string.h>
27#include <errno.h>
28#include <assert.h>
29#include <stdio.h>
30
31#if defined(HAVE_PTHREADS)
32# include <pthread.h>
33#endif
34
35#include <utils/Vector.h>
36
37using namespace android;
38
39namespace android {
40
41/*
42 * Like strdup(), but uses C++ "new" operator instead of malloc.
43 */
44char* strdupNew(const char* str)
45{
46    char* newStr;
47    int len;
48
49    if (str == NULL)
50        return NULL;
51
52    len = strlen(str);
53    newStr = new char[len+1];
54    memcpy(newStr, str, len+1);
55
56    return newStr;
57}
58
59/*
60 * Concatenate an argument vector.
61 */
62char* concatArgv(int argc, const char* const argv[])
63{
64    char* newStr = NULL;
65    int len, totalLen, posn, idx;
66
67    /*
68     * First, figure out the total length.
69     */
70    totalLen = idx = 0;
71    while (1) {
72        if (idx == argc || argv[idx] == NULL)
73            break;
74        if (idx)
75            totalLen++;  // leave a space between args
76        totalLen += strlen(argv[idx]);
77        idx++;
78    }
79
80    /*
81     * Alloc the string.
82     */
83    newStr = new char[totalLen +1];
84    if (newStr == NULL)
85        return NULL;
86
87    /*
88     * Finally, allocate the string and copy data over.
89     */
90    idx = posn = 0;
91    while (1) {
92        if (idx == argc || argv[idx] == NULL)
93            break;
94        if (idx)
95            newStr[posn++] = ' ';
96
97        len = strlen(argv[idx]);
98        memcpy(&newStr[posn], argv[idx], len);
99        posn += len;
100
101        idx++;
102    }
103
104    assert(posn == totalLen);
105    newStr[posn] = '\0';
106
107    return newStr;
108}
109
110/*
111 * Count the #of args in an argument vector.  Don't count the final NULL.
112 */
113int countArgv(const char* const argv[])
114{
115    int count = 0;
116
117    while (argv[count] != NULL)
118        count++;
119
120    return count;
121}
122
123
124#include <stdio.h>
125/*
126 * Get a file's type.
127 */
128FileType getFileType(const char* fileName)
129{
130    struct stat sb;
131
132    if (stat(fileName, &sb) < 0) {
133        if (errno == ENOENT || errno == ENOTDIR)
134            return kFileTypeNonexistent;
135        else {
136            fprintf(stderr, "getFileType got errno=%d on '%s'\n",
137                errno, fileName);
138            return kFileTypeUnknown;
139        }
140    } else {
141        if (S_ISREG(sb.st_mode))
142            return kFileTypeRegular;
143        else if (S_ISDIR(sb.st_mode))
144            return kFileTypeDirectory;
145        else if (S_ISCHR(sb.st_mode))
146            return kFileTypeCharDev;
147        else if (S_ISBLK(sb.st_mode))
148            return kFileTypeBlockDev;
149        else if (S_ISFIFO(sb.st_mode))
150            return kFileTypeFifo;
151#ifdef HAVE_SYMLINKS
152        else if (S_ISLNK(sb.st_mode))
153            return kFileTypeSymlink;
154        else if (S_ISSOCK(sb.st_mode))
155            return kFileTypeSocket;
156#endif
157        else
158            return kFileTypeUnknown;
159    }
160}
161
162/*
163 * Get a file's modification date.
164 */
165time_t getFileModDate(const char* fileName)
166{
167    struct stat sb;
168
169    if (stat(fileName, &sb) < 0)
170        return (time_t) -1;
171
172    return sb.st_mtime;
173}
174
175/*
176 * Round up to the next highest power of 2.
177 *
178 * Found on http://graphics.stanford.edu/~seander/bithacks.html.
179 */
180unsigned int roundUpPower2(unsigned int val)
181{
182    val--;
183    val |= val >> 1;
184    val |= val >> 2;
185    val |= val >> 4;
186    val |= val >> 8;
187    val |= val >> 16;
188    val++;
189
190    return val;
191}
192
193struct sysprop_change_callback_info {
194    sysprop_change_callback callback;
195    int priority;
196};
197
198#if defined(HAVE_PTHREADS)
199static pthread_mutex_t gSyspropMutex = PTHREAD_MUTEX_INITIALIZER;
200static Vector<sysprop_change_callback_info>* gSyspropList = NULL;
201#endif
202
203void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
204#if defined(HAVE_PTHREADS)
205    pthread_mutex_lock(&gSyspropMutex);
206    if (gSyspropList == NULL) {
207        gSyspropList = new Vector<sysprop_change_callback_info>();
208    }
209    sysprop_change_callback_info info;
210    info.callback = cb;
211    info.priority = priority;
212    bool added = false;
213    for (size_t i=0; i<gSyspropList->size(); i++) {
214        if (priority >= gSyspropList->itemAt(i).priority) {
215            gSyspropList->insertAt(info, i);
216            added = true;
217            break;
218        }
219    }
220    if (!added) {
221        gSyspropList->add(info);
222    }
223    pthread_mutex_unlock(&gSyspropMutex);
224#endif
225}
226
227void report_sysprop_change() {
228#if defined(HAVE_PTHREADS)
229    pthread_mutex_lock(&gSyspropMutex);
230    Vector<sysprop_change_callback_info> listeners;
231    if (gSyspropList != NULL) {
232        listeners = *gSyspropList;
233    }
234    pthread_mutex_unlock(&gSyspropMutex);
235
236    //ALOGI("Reporting sysprop change to %d listeners", listeners.size());
237    for (size_t i=0; i<listeners.size(); i++) {
238        listeners[i].callback();
239    }
240#endif
241}
242
243}; // namespace android
244